{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# default_exp utils"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Utilities\n",
    "\n",
    "> Helper functions used throughout the library not related to timeseries data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from tsai.imports import *\n",
    "from fastcore.test import *\n",
    "import inspect\n",
    "import sklearn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ensure these folders exist for testing purposes\n",
    "fns = ['data', 'export', 'models']\n",
    "for fn in fns: \n",
    "    path = Path('.')/fn\n",
    "    if not os.path.exists(path): os.makedirs(path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def totensor(o):\n",
    "    if isinstance(o, torch.Tensor): return o\n",
    "    elif isinstance(o, np.ndarray):  return torch.from_numpy(o)\n",
    "    elif isinstance(o, pd.DataFrame): return torch.from_numpy(o.values)\n",
    "    else: \n",
    "        try: return torch.tensor(o)\n",
    "        except: warnings.warn(f\"Can't convert {type(o)} to torch.Tensor\", Warning)\n",
    "\n",
    "\n",
    "def toarray(o):\n",
    "    if isinstance(o, np.ndarray): return o\n",
    "    elif isinstance(o, torch.Tensor): return o.cpu().numpy()\n",
    "    elif isinstance(o, pd.DataFrame): return o.values\n",
    "    else:\n",
    "        try: return np.asarray(o)\n",
    "        except: warnings.warn(f\"Can't convert {type(o)} to np.array\", Warning)\n",
    "    \n",
    "    \n",
    "def toL(o):\n",
    "    if isinstance(o, L): return o\n",
    "    elif isinstance(o, (np.ndarray, torch.Tensor)): return L(o.tolist())\n",
    "    else:\n",
    "        try: return L(o)\n",
    "        except: warnings.warn(f'passed object needs to be of type L, list, np.ndarray or torch.Tensor but is {type(o)}', Warning)\n",
    "\n",
    "\n",
    "def to3dtensor(o):\n",
    "    o = totensor(o)\n",
    "    if o.ndim == 3: return o\n",
    "    elif o.ndim == 1: return o[None, None]\n",
    "    elif o.ndim == 2: return o[:, None]\n",
    "    assert False, f'Please, review input dimensions {o.ndim}'\n",
    "\n",
    "\n",
    "def to2dtensor(o):\n",
    "    o = totensor(o)\n",
    "    if o.ndim == 2: return o\n",
    "    elif o.ndim == 1: return o[None]\n",
    "    elif o.ndim == 3: return o[0]\n",
    "    assert False, f'Please, review input dimensions {o.ndim}'\n",
    "\n",
    "\n",
    "def to1dtensor(o):\n",
    "    o = totensor(o)\n",
    "    if o.ndim == 1: return o\n",
    "    elif o.ndim == 3: return o[0,0]\n",
    "    if o.ndim == 2: return o[0]\n",
    "    assert False, f'Please, review input dimensions {o.ndim}'\n",
    "\n",
    "\n",
    "def to3darray(o):\n",
    "    o = toarray(o)\n",
    "    if o.ndim == 3: return o\n",
    "    elif o.ndim == 1: return o[None, None]\n",
    "    elif o.ndim == 2: return o[:, None]\n",
    "    assert False, f'Please, review input dimensions {o.ndim}'\n",
    "\n",
    "\n",
    "def to2darray(o):\n",
    "    o = toarray(o)\n",
    "    if o.ndim == 2: return o\n",
    "    elif o.ndim == 1: return o[None]\n",
    "    elif o.ndim == 3: return o[0]\n",
    "    assert False, f'Please, review input dimensions {o.ndim}'\n",
    "\n",
    "\n",
    "def to1darray(o):\n",
    "    o = toarray(o)\n",
    "    if o.ndim == 1: return o\n",
    "    elif o.ndim == 3: o = o[0,0]\n",
    "    elif o.ndim == 2: o = o[0]\n",
    "    assert False, f'Please, review input dimensions {o.ndim}'\n",
    "    \n",
    "    \n",
    "def to3d(o):\n",
    "    if o.ndim == 3: return o\n",
    "    if isinstance(o, (np.ndarray, pd.DataFrame)): return to3darray(o)\n",
    "    if isinstance(o, torch.Tensor): return to3dtensor(o)\n",
    "    \n",
    "    \n",
    "def to2d(o):\n",
    "    if o.ndim == 2: return o\n",
    "    if isinstance(o, np.ndarray): return to2darray(o)\n",
    "    if isinstance(o, torch.Tensor): return to2dtensor(o)\n",
    "    \n",
    "    \n",
    "def to1d(o):\n",
    "    if o.ndim == 1: return o\n",
    "    if isinstance(o, np.ndarray): return to1darray(o)\n",
    "    if isinstance(o, torch.Tensor): return to1dtensor(o)\n",
    "    \n",
    "    \n",
    "def to2dPlus(o):\n",
    "    if o.ndim >= 2: return o\n",
    "    if isinstance(o, np.ndarray): return to2darray(o)\n",
    "    elif isinstance(o, torch.Tensor): return to2dtensor(o)\n",
    "    \n",
    "    \n",
    "def to3dPlus(o):\n",
    "    if o.ndim >= 3: return o\n",
    "    if isinstance(o, np.ndarray): return to3darray(o)\n",
    "    elif isinstance(o, torch.Tensor): return to3dtensor(o)\n",
    "    \n",
    "    \n",
    "def to2dPlusTensor(o):\n",
    "    return to2dPlus(totensor(o))\n",
    "\n",
    "\n",
    "def to2dPlusArray(o):\n",
    "    return to2dPlus(toarray(o))\n",
    "\n",
    "\n",
    "def to3dPlusTensor(o):\n",
    "    return to3dPlus(totensor(o))\n",
    "\n",
    "\n",
    "def to3dPlusArray(o):\n",
    "    return to3dPlus(toarray(o))\n",
    "\n",
    "\n",
    "def todtype(dtype):\n",
    "    def _to_type(o, dtype=dtype):\n",
    "        if o.dtype == dtype: return o\n",
    "        elif isinstance(o, torch.Tensor): o = o.to(dtype=dtype)\n",
    "        elif isinstance(o, np.ndarray): o = o.astype(dtype)\n",
    "        return o\n",
    "    return _to_type"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.random.rand(100).astype(np.float32)\n",
    "b = torch.from_numpy(a).float()\n",
    "test_eq(totensor(a), b)\n",
    "test_eq(a, toarray(b))\n",
    "test_eq(to3dtensor(a).ndim, 3)\n",
    "test_eq(to2dtensor(a).ndim, 2)\n",
    "test_eq(to1dtensor(a).ndim, 1)\n",
    "test_eq(to3darray(b).ndim, 3)\n",
    "test_eq(to2darray(b).ndim, 2)\n",
    "test_eq(to1darray(b).ndim, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = np.random.rand(10, 20)\n",
    "df = pd.DataFrame(data)\n",
    "df['target'] = np.random.randint(0, 3, len(df))\n",
    "X = df[df.columns[:-1]]\n",
    "y = df['target']\n",
    "test_eq(to3darray(X).shape, (10, 1, 20))\n",
    "test_eq(toarray(y).shape, (10,))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def bytes2size(size_bytes):\n",
    "    if size_bytes == 0: return \"0B\"\n",
    "    size_name = (\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\")\n",
    "    i = int(math.floor(math.log(size_bytes, 1024)))\n",
    "    p = math.pow(1024, i)\n",
    "    s = round(size_bytes / p, 2)\n",
    "    return \"%s %s\" % (s, size_name[i])\n",
    "\n",
    "def bytes2GB(byts):\n",
    "    return round(byts / math.pow(1024, 3), 2)\n",
    "\n",
    "def get_size(o, return_str=False):\n",
    "    s = sys.getsizeof(o)\n",
    "    if return_str: return bytes2size(s)\n",
    "    else: return s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.random.rand(10, 5, 3)\n",
    "test_eq(get_size(a, True), '1.3 KB')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def is_file(file_path):\n",
    "    return os.path.isfile(file_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_eq(is_file(\"001_utils.ipynb\"), True)\n",
    "test_eq(is_file(\"utils.ipynb\"), False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def delete_all_in_dir(tgt_dir, exception=None):\n",
    "    if exception is not None and len(L(exception)) > 1: exception = tuple(exception)\n",
    "    for file in os.listdir(tgt_dir):\n",
    "        if exception is not None and file.endswith(exception): continue\n",
    "        file_path = os.path.join(tgt_dir, file)\n",
    "        if os.path.isfile(file_path) or os.path.islink(file_path): os.unlink(file_path)\n",
    "        elif os.path.isdir(file_path): shutil.rmtree(file_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def reverse_dict(dictionary): \n",
    "    return {v: k for k, v in dictionary.items()}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def is_tuple(o): return isinstance(o, tuple)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def itemify(*o, tup_id=None): \n",
    "    o = [o_ for o_ in L(*o) if o_ is not None]\n",
    "    items = L(o).zip()\n",
    "    if tup_id is not None: return L([item[tup_id] for item in items])\n",
    "    else: return items"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(1, 4), (2, 5), (3, 6)]\n",
      "[(1,), (2,), (3,)]\n",
      "[(1, 4), (2, 5), (3, 6)]\n"
     ]
    }
   ],
   "source": [
    "a = [1, 2, 3]\n",
    "b = [4, 5, 6]\n",
    "print(itemify(a, b))\n",
    "test_eq(len(itemify(a, b)), len(a))\n",
    "a = [1, 2, 3]\n",
    "b = None\n",
    "print(itemify(a, b))\n",
    "test_eq(len(itemify(a, b)), len(a))\n",
    "a = [1, 2, 3]\n",
    "b = [4, 5, 6]\n",
    "c = None\n",
    "print(itemify(a, b, c))\n",
    "test_eq(len(itemify(a, b, c)), len(a))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def isnone(o):\n",
    "    return o is None\n",
    "\n",
    "def exists(o): return o is not None\n",
    "\n",
    "def ifelse(a, b, c):\n",
    "    \"`b` if `a` is True else `c`\"\n",
    "    return b if a else c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.array(3)\n",
    "test_eq(isnone(a), False)\n",
    "test_eq(exists(a), True)\n",
    "b = None\n",
    "test_eq(isnone(b), True)\n",
    "test_eq(exists(b), False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def is_not_close(a, b, eps=1e-5):\n",
    "    \"Is `a` within `eps` of `b`\"\n",
    "    if hasattr(a, '__array__') or hasattr(b, '__array__'):\n",
    "        return (abs(a - b) > eps).all()\n",
    "    if isinstance(a, (Iterable, Generator)) or isinstance(b, (Iterable, Generator)):\n",
    "        return is_not_close(np.array(a), np.array(b), eps=eps)\n",
    "    return abs(a - b) > eps\n",
    "\n",
    "\n",
    "def test_not_close(a, b, eps=1e-5):\n",
    "    \"`test` that `a` is within `eps` of `b`\"\n",
    "    test(a, b, partial(is_not_close, eps=eps), 'not_close')\n",
    "\n",
    "\n",
    "def test_type(a, b):\n",
    "    return test_eq(type(a), type(b))\n",
    "\n",
    "\n",
    "def test_ok(f, *args, **kwargs):\n",
    "    try: \n",
    "        f(*args, **kwargs)\n",
    "        e = 0\n",
    "    except: \n",
    "        e = 1\n",
    "        pass\n",
    "    test_eq(e, 0)\n",
    "    \n",
    "def test_not_ok(f, *args, **kwargs):\n",
    "    try: \n",
    "        f(*args, **kwargs)\n",
    "        e = 0\n",
    "    except: \n",
    "        e = 1\n",
    "        pass\n",
    "    test_eq(e, 1)\n",
    "    \n",
    "def test_error(error, f, *args, **kwargs):\n",
    "    try: f(*args, **kwargs)\n",
    "    except Exception as e: \n",
    "        test_eq(str(e), error)\n",
    "        \n",
    "        \n",
    "def test_eq_nan(a,b):\n",
    "    \"`test` that `a==b` excluding nan values (valid for torch.Tensor and np.ndarray)\"\n",
    "    mask_a = torch.isnan(a) if isinstance(a, torch.Tensor) else np.isnan(a)\n",
    "    mask_b = torch.isnan(b) if isinstance(b, torch.Tensor) else np.isnan(b)\n",
    "    test(a[~mask_a],b[~mask_b],equals, '==')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def assert_fn(*args, **kwargs): assert False, 'assertion test'\n",
    "test_error('assertion test', assert_fn, 35, a=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def test_gt(a,b):\n",
    "    \"`test` that `a>b`\"\n",
    "    test(a,b,gt,'>')\n",
    "\n",
    "def test_ge(a,b):\n",
    "    \"`test` that `a>=b`\"\n",
    "    test(a,b,ge,'>')\n",
    "    \n",
    "def test_lt(a,b):\n",
    "    \"`test` that `a>b`\"\n",
    "    test(a,b,lt,'<')\n",
    "\n",
    "def test_le(a,b):\n",
    "    \"`test` that `a>b`\"\n",
    "    test(a,b,le,'<=')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_ok(test_gt, 5, 4)\n",
    "test_not_ok(test_gt, 4, 4)\n",
    "test_ok(test_ge, 4, 4)\n",
    "test_not_ok(test_ge, 3, 4)\n",
    "\n",
    "test_ok(test_lt, 3, 4)\n",
    "test_not_ok(test_lt, 4, 4)\n",
    "test_ok(test_le, 4, 4)\n",
    "test_not_ok(test_le, 5, 4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = torch.rand(100)\n",
    "t[t<.5] = np.nan\n",
    "test_ne(t, t)\n",
    "test_eq_nan(t, t)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def stack(o, axis=0, retain=True):\n",
    "    if hasattr(o, '__array__'): return o\n",
    "    if isinstance(o[0], torch.Tensor):\n",
    "        return retain_type(torch.stack(tuple(o), dim=axis),  o[0]) if retain else torch.stack(tuple(o), dim=axis)\n",
    "    else:\n",
    "        return retain_type(np.stack(o, axis), o[0]) if retain else np.stack(o, axis)\n",
    "    \n",
    "    \n",
    "def stack_pad(o, padding_value=np.nan):\n",
    "    'Converts a an iterable into a numpy array using padding if necessary'\n",
    "    row_length = len(max(o, key=len))\n",
    "    result = np.full((len(o), row_length), padding_value)\n",
    "    for i,row in enumerate(o): result[i, :len(row)] = row\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [[0,1,2], [4,5,6,7]]\n",
    "test_eq(stack_pad(a).shape, (2, 4))\n",
    "test_eq(type(stack_pad(a)), np.ndarray)\n",
    "test_eq(np.isnan(stack_pad(a)).sum(), 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.random.rand(2, 3, 4)\n",
    "t = torch.from_numpy(a)\n",
    "test_eq_type(stack(itemify(a, tup_id=0)), a)\n",
    "test_eq_type(stack(itemify(t, tup_id=0)), t)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def match_seq_len(*arrays):\n",
    "    max_len = stack([x.shape[-1] for x in arrays]).max()\n",
    "    return [np.pad(x, pad_width=((0,0), (0,0), (max_len - x.shape[-1], 0)), mode='constant', constant_values=0) for x in arrays]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.random.rand(10, 5, 8)\n",
    "b = np.random.rand(3, 5, 10)\n",
    "c, d = match_seq_len(a, b)\n",
    "test_eq(c.shape[-1], d.shape[-1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def random_shuffle(o, random_state=None):\n",
    "    res = sklearn.utils.shuffle(o, random_state=random_state)\n",
    "    if isinstance(o, L): return L(list(res))\n",
    "    return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.arange(10)\n",
    "test_eq_type(random_shuffle(a, 1), np.array([2, 9, 6, 4, 0, 3, 1, 7, 8, 5]))\n",
    "t = torch.arange(10)\n",
    "test_eq_type(random_shuffle(t, 1), tensor([2, 9, 6, 4, 0, 3, 1, 7, 8, 5]))\n",
    "l = list(a)\n",
    "test_eq(random_shuffle(l, 1), [2, 9, 6, 4, 0, 3, 1, 7, 8, 5])\n",
    "l2 = L(l)\n",
    "test_eq_type(random_shuffle(l2, 1), L([2, 9, 6, 4, 0, 3, 1, 7, 8, 5]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def cat2int(o):\n",
    "    cat = Categorize()\n",
    "    cat.setup(o)\n",
    "    return stack(TfmdLists(o, cat)[:])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.array(['b', 'a', 'a', 'b', 'a', 'b', 'a'])\n",
    "test_eq_type(cat2int(a), TensorCategory([1, 0, 0, 1, 0, 1, 0]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "TensorBase([1, 2, 3])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "TensorBase([1,2,3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def cycle_dl(dl): \n",
    "    for _ in dl: _\n",
    "        \n",
    "def cycle_dl_to_device(dl):\n",
    "    for bs in dl: [b.to(default_device()) for b in bs]\n",
    "        \n",
    "def cycle_dl_estimate(dl, iters=10):\n",
    "    iters = min(iters, len(dl))\n",
    "    iterator = iter(dl)\n",
    "    timer.start(False)\n",
    "    for _ in range(iters): next(iterator)\n",
    "    t = timer.stop()\n",
    "    return (t/iters * len(dl)).total_seconds()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def cache_data(o, slice_len=10_000, verbose=False):\n",
    "    start = 0\n",
    "    n_loops = (len(o) - 1) // slice_len + 1\n",
    "    pv(f'{n_loops} loops', verbose)\n",
    "    timer.start(False)\n",
    "    for i in range(n_loops):\n",
    "        o[slice(start,start + slice_len)]        \n",
    "        if verbose and (i+1) % 10 == 0: print(f'{i+1:4} elapsed time: {timer.elapsed()}')\n",
    "        start += slice_len\n",
    "    pv(f'{i+1:4} total time  : {timer.stop()}\\n', verbose)\n",
    "    \n",
    "memmap2cache =  cache_data\n",
    "cache_memmap = cache_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_func_defaults(f): \n",
    "    fa = inspect.getfullargspec(f)\n",
    "    if fa.defaults is None: return dict(zip(fa.args, [''] * (len(fa.args))))\n",
    "    else: return dict(zip(fa.args, [''] * (len(fa.args) - len(fa.defaults)) + list(fa.defaults)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_idx_from_df_col_vals(df, col, val_list):\n",
    "    return [df[df[col] == val].index[0] for val in val_list]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_sublist_idxs(aList, bList):\n",
    "    \"Get idxs that when applied to aList will return bList. aList must contain all values in bList\"\n",
    "    sorted_aList = aList[np.argsort(aList)]\n",
    "    return np.argsort(aList)[np.searchsorted(sorted_aList, bList)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([3, 5, 7, 1, 9, 8, 6, 2])\n",
    "y = np.array([6, 1, 5, 7])\n",
    "idx = get_sublist_idxs(x, y)\n",
    "test_eq(x[idx], y)\n",
    "x = np.array([3, 5, 7, 1, 9, 8, 6, 6, 2])\n",
    "y = np.array([6, 1, 5, 7, 5])\n",
    "idx = get_sublist_idxs(x, y)\n",
    "test_eq(x[idx], y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def flatten_list(l):\n",
    "    return [item for sublist in l for item in sublist]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def display_pd_df(df, max_rows:Union[bool, int]=False, max_columns:Union[bool, int]=False):\n",
    "    if max_rows:\n",
    "        old_max_rows = pd.get_option('display.max_rows')\n",
    "        if max_rows is not True and isinstance(max_rows, Integral): pd.set_option('display.max_rows', max_rows)\n",
    "        else: pd.set_option('display.max_rows', df.shape[0])\n",
    "    if max_columns:\n",
    "        old_max_columns = pd.get_option('display.max_columns')\n",
    "        if max_columns is not True and isinstance(max_columns, Integral): pd.set_option('display.max_columns', max_columns)\n",
    "        else: pd.set_option('display.max_columns', df.shape[1])\n",
    "    display(df)\n",
    "    if max_rows: pd.set_option('display.max_rows', old_max_rows)\n",
    "    if max_columns: pd.set_option('display.max_columns', old_max_columns)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>0</th>\n",
       "      <th>...</th>\n",
       "      <th>24</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.186560</td>\n",
       "      <td>...</td>\n",
       "      <td>0.033775</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>69</th>\n",
       "      <td>0.334533</td>\n",
       "      <td>...</td>\n",
       "      <td>0.059145</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>70 rows × 25 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "          0   ...        24\n",
       "0   0.186560  ...  0.033775\n",
       "..       ...  ...       ...\n",
       "69  0.334533  ...  0.059145\n",
       "\n",
       "[70 rows x 25 columns]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "old_max_rows, old_max_columns = pd.get_option('display.max_rows'), pd.get_option('display.max_columns')\n",
    "df = pd.DataFrame(np.random.rand(70, 25))\n",
    "display_pd_df(df, max_rows=2, max_columns=3)\n",
    "test_eq(old_max_rows, pd.get_option('display.max_rows'))\n",
    "test_eq(old_max_columns, pd.get_option('display.max_columns'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def ttest(data1, data2, equal_var=False):\n",
    "    \"Calculates t-statistic and p-value based on 2 sample distributions\"\n",
    "    t_stat, p_value = scipy.stats.ttest_ind(data1, data2, equal_var=equal_var)\n",
    "    return t_stat, np.sign(t_stat) * p_value\n",
    "\n",
    "def tscore(o): \n",
    "    if o.std() == 0: return 0\n",
    "    else: return np.sqrt(len(o)) * o.mean() / o.std()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "(2.534180499618029, 0.012316235357575254)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.random.normal(0.5, 1, 100)\n",
    "b = np.random.normal(0.15, .5, 50)\n",
    "plt.hist(a, 50)\n",
    "plt.hist(b, 50)\n",
    "plt.show()\n",
    "ttest(a,b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(4.3082635435836725, tensor(4.7953))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.random.normal(0.5, 1, 100)\n",
    "t = torch.normal(0.5, 1, (100, ))\n",
    "tscore(a), tscore(t)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def ttest_tensor(a, b):\n",
    "    \"differentiable pytorch function equivalent to scipy.stats.ttest_ind with equal_var=False\"\n",
    "    # calculate standard errors\n",
    "    se1, se2 = torch.std(a)/np.sqrt(len(a)), torch.std(b)/np.sqrt(len(b))\n",
    "    # standard error on the difference between the samples\n",
    "    sed = torch.sqrt(se1**2.0 + se2**2.0)\n",
    "    # calculate the t statistic\n",
    "    t_stat = (torch.mean(a) - torch.mean(b)) / sed\n",
    "    return t_stat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(3.1260, grad_fn=<DivBackward0>)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = torch.rand(100).requires_grad_(True) + .1\n",
    "b = torch.rand(100).requires_grad_(True)\n",
    "ttest_tensor(a, b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(-0.22264158038394366, -0.18997899789978998)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#export\n",
    "from scipy.stats import pearsonr, spearmanr\n",
    "\n",
    "def pcc(a, b):\n",
    "    return pearsonr(a, b)[0]\n",
    "\n",
    "def scc(a, b):\n",
    "    return spearmanr(a, b)[0]\n",
    "\n",
    "a = np.random.normal(0.5, 1, 100)\n",
    "b = np.random.normal(0.15, .5, 100)\n",
    "pcc(a, b), scc(a, b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def remove_fn(fn, verbose=False):\n",
    "    \"Removes a file (fn) if exists\"\n",
    "    try: \n",
    "        os.remove(fn)\n",
    "        pv(f'{fn} file removed', verbose)\n",
    "    except OSError: \n",
    "        pv(f'{fn} does not exist', verbose)\n",
    "        pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def npsave(array_fn, array, verbose=True):\n",
    "    remove_fn(array_fn, verbose)\n",
    "    pv(f'saving {array_fn}...', verbose)\n",
    "    np.save(array_fn, array)\n",
    "    pv(f'...{array_fn} saved', verbose)\n",
    "    \n",
    "np_save = npsave"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "data/remove_fn_test.npy does not exist\n",
      "saving data/remove_fn_test.npy...\n",
      "...data/remove_fn_test.npy saved\n",
      "data/remove_fn_test.npy file removed\n",
      "data/remove_fn_test.npy does not exist\n"
     ]
    }
   ],
   "source": [
    "fn = 'data/remove_fn_test.npy'\n",
    "a = np.zeros(1)\n",
    "npsave(fn, a)\n",
    "del a\n",
    "np.load(fn, mmap_mode='r+')\n",
    "remove_fn(fn, True)\n",
    "remove_fn(fn, True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def permute_2D(array, axis=None):\n",
    "    \"Permute rows or columns in an array. This can be used, for example, in feature permutation\"\n",
    "    if axis == 0: return array[np.random.randn(*array.shape).argsort(axis=0), np.arange(array.shape[-1])[None, :]] \n",
    "    elif axis == 1 or axis == -1: return array[np.arange(len(array))[:,None], np.random.randn(*array.shape).argsort(axis=1)] \n",
    "    return array[np.random.randn(*array.shape).argsort(axis=0), np.random.randn(*array.shape).argsort(axis=1)] "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = np.arange(100 * 50).reshape(100, 50) \n",
    "test_eq(permute_2D(s, axis=0).mean(0), s.mean(0))\n",
    "test_ne(permute_2D(s, axis=0), s)\n",
    "test_eq(permute_2D(s, axis=1).mean(1), s.mean(1))\n",
    "test_ne(permute_2D(s, axis=1), s)\n",
    "test_ne(permute_2D(s), s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def random_normal():\n",
    "    \"Returns a number between -1 and 1 with a normal distribution\"\n",
    "    while True:\n",
    "        o = np.random.normal(loc=0., scale=1/3)\n",
    "        if abs(o) <= 1: break\n",
    "    return o\n",
    "\n",
    "def random_half_normal():\n",
    "    \"Returns a number between 0 and 1 with a half-normal distribution\"\n",
    "    while True:\n",
    "        o = abs(np.random.normal(loc=0., scale=1/3))\n",
    "        if o <= 1: break\n",
    "    return o\n",
    "\n",
    "def random_normal_tensor(shape=1, device=None):\n",
    "    \"Returns a tensor of a predefined shape between -1 and 1 with a normal distribution\"\n",
    "    return torch.empty(shape, device=device).normal_(mean=0, std=1/3).clamp_(-1, 1)\n",
    "\n",
    "def random_half_normal_tensor(shape=1, device=None):\n",
    "    \"Returns a tensor of a predefined shape between 0 and 1 with a half-normal distribution\"\n",
    "    return abs(torch.empty(shape, device=device).normal_(mean=0, std=1/3)).clamp_(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from matplotlib.backends.backend_agg import FigureCanvasAgg\n",
    "\n",
    "def default_dpi():\n",
    "    DPI = plt.gcf().get_dpi()\n",
    "    plt.close()\n",
    "    return int(DPI)\n",
    "\n",
    "def get_plot_fig(size=None, dpi=default_dpi()):\n",
    "    fig = plt.figure(figsize=(size / dpi, size / dpi), dpi=dpi, frameon=False) if size else plt.figure()\n",
    "    ax = fig.add_axes([0,0,1,1])\n",
    "    ax.spines['top'].set_visible(False)\n",
    "    ax.spines['right'].set_visible(False)\n",
    "    ax.spines['bottom'].set_visible(False)\n",
    "    ax.spines['left'].set_visible(False)\n",
    "    ax.get_xaxis().set_visible(False)\n",
    "    ax.get_yaxis().set_visible(False)\n",
    "    config = plt.gcf()\n",
    "    plt.close('all')\n",
    "    return config\n",
    "\n",
    "def fig2buf(fig):\n",
    "    canvas = FigureCanvasAgg(fig)\n",
    "    fig.canvas.draw()\n",
    "    return np.asarray(canvas.buffer_rgba())[..., :3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "72"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "default_dpi()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def plot_scatter(x, y, deg=1):\n",
    "    linreg = sp.stats.linregress(x, y)\n",
    "    plt.scatter(x, y, label=f'R2:{linreg.rvalue:.2f}', color='lime', edgecolor='black', alpha=.5)\n",
    "    plt.plot(np.unique(x), np.poly1d(np.polyfit(x, y, deg))(np.unique(x)), color='r')\n",
    "    plt.legend(loc='best')\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "a = np.random.rand(100)\n",
    "b = np.random.rand(100)**2\n",
    "plot_scatter(a, b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_idxs(o, aList): return array([o.tolist().index(v) for v in aList])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = random_shuffle(np.arange(100, 200))\n",
    "b = np.random.choice(a, 10, False)\n",
    "idxs = get_idxs(a, b)\n",
    "test_eq(a[idxs], b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def apply_cmap(o, cmap):\n",
    "    o = toarray(o)\n",
    "    out = plt.get_cmap(cmap)(o)[..., :3]\n",
    "    out = tensor(out).squeeze(1)\n",
    "    return out.permute(0, 3, 1, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.random.rand(16, 1, 40, 50)\n",
    "s = L(a.shape)\n",
    "s[1] = 3\n",
    "test_eq(L(apply_cmap(a, 'viridis').shape), s)\n",
    "\n",
    "s[0] = 1\n",
    "a = np.random.rand(1, 40, 50)\n",
    "test_eq(L(apply_cmap(a, 'viridis').shape), s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def torch_tile(a, n_tile, dim=0):\n",
    "    init_dim = a.size(dim)\n",
    "    repeat_idx = [1] * a.dim()\n",
    "    repeat_idx[dim] = n_tile\n",
    "    a = a.repeat(*(repeat_idx))\n",
    "    order_index = torch.cat([init_dim * torch.arange(n_tile) + i for i in range(init_dim)]).to(device=a.device)\n",
    "    return torch.index_select(a, dim, order_index)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_eq(torch_tile(torch.arange(2), 3), tensor([0, 0, 0, 1, 1, 1]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def to_tsfresh_df(ts):\n",
    "    r\"\"\"Prepares a time series (Tensor/ np.ndarray) to be used as a tsfresh dataset to allow feature extraction\"\"\"\n",
    "    ts = to3d(ts)\n",
    "    if isinstance(ts, np.ndarray):\n",
    "        ids = np.repeat(np.arange(len(ts)), ts.shape[-1]).reshape(-1,1)\n",
    "        joint_ts =  ts.transpose(0,2,1).reshape(-1, ts.shape[1])\n",
    "        cols = ['id'] + np.arange(ts.shape[1]).tolist()\n",
    "        df = pd.DataFrame(np.concatenate([ids, joint_ts], axis=1), columns=cols)\n",
    "    elif isinstance(ts, torch.Tensor):\n",
    "        ids = torch_tile(torch.arange(len(ts)), ts.shape[-1]).reshape(-1,1)\n",
    "        joint_ts =  ts.transpose(1,2).reshape(-1, ts.shape[1])\n",
    "        cols = ['id']+np.arange(ts.shape[1]).tolist()\n",
    "        df = pd.DataFrame(torch.cat([ids, joint_ts], dim=1).numpy(), columns=cols)\n",
    "    df['id'] = df['id'].astype(int)\n",
    "    df.reset_index(drop=True, inplace=True)\n",
    "    return df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ts = torch.rand(16, 3, 20)\n",
    "a = to_tsfresh_df(ts)\n",
    "ts = ts.numpy()\n",
    "b = to_tsfresh_df(ts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from scipy.stats import skew, kurtosis\n",
    "\n",
    "def pcorr(a, b): \n",
    "    return scipy.stats.pearsonr(a, b)\n",
    "\n",
    "def scorr(a, b): \n",
    "    corr = scipy.stats.spearmanr(a, b)\n",
    "    return corr[0], corr[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def torch_diff(t, lag=1, pad=True):\n",
    "    import torch.nn.functional as F\n",
    "    diff = t[..., lag:] - t[..., :-lag]\n",
    "    if pad: return F.pad(diff, (lag,0))\n",
    "    else: return diff"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = torch.arange(24).reshape(2,3,4)\n",
    "test_eq(torch_diff(t, 1)[..., 1:].float().mean(), 1.)\n",
    "test_eq(torch_diff(t, 2)[..., 2:].float().mean(), 2.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_outliers_IQR(o, axis=None, quantile_range=(25.0, 75.0)):\n",
    "    tt = False\n",
    "    if isinstance(o, torch.Tensor):\n",
    "        tt = True\n",
    "        device = o.device\n",
    "        tdtype = o.dtype\n",
    "        o = o.detach().cpu().numpy()\n",
    "    Q1 = np.nanpercentile(o, quantile_range[0], axis=axis, keepdims=axis is not None)\n",
    "    Q3 = np.nanpercentile(o, quantile_range[1], axis=axis, keepdims=axis is not None)\n",
    "    IQR = Q3 - Q1\n",
    "    if tt:\n",
    "        Q1 = torch.tensor(Q1, dtype=tdtype, device=device)\n",
    "        Q3 = torch.tensor(Q3, dtype=tdtype, device=device)\n",
    "        IQR = torch.tensor(IQR, dtype=tdtype, device=device)\n",
    "    return Q1 - 1.5 * IQR, Q3 + 1.5 * IQR\n",
    "\n",
    "def clip_outliers(o, axis=None):\n",
    "    min_outliers, max_outliers = get_outliers_IQR(o, axis=axis)\n",
    "    if isinstance(o, (np.ndarray, pd.core.series.Series)):\n",
    "        return np.clip(o, min_outliers, max_outliers)\n",
    "    elif isinstance(o, torch.Tensor):\n",
    "        return torch.clamp(o, min_outliers, max_outliers)\n",
    "\n",
    "def get_percentile(o, percentile, axis=None):\n",
    "    if isinstance(o, torch.Tensor): o = o.detach().cpu().numpy()\n",
    "    return np.nanpercentile(o, percentile, axis=axis, keepdims=axis is not None)\n",
    "\n",
    "def torch_clamp(o, min=None, max=None):\n",
    "    r\"\"\"Clamp torch.Tensor using 1 or multiple dimensions\"\"\"\n",
    "    if min is not None: o = torch.max(o, min)\n",
    "    if max is not None: o = torch.min(o, max)\n",
    "    return o"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = torch.randn(2,3,100)\n",
    "test_eq(type(get_outliers_IQR(t, -1)[0]), torch.Tensor)\n",
    "a = np.random.randn(2,3,100)\n",
    "test_eq(type(get_outliers_IQR(a, -1)[0]), np.ndarray)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def torch_slice_by_dim(t, index, dim=-1, **kwargs):\n",
    "    if not isinstance(index, torch.Tensor): index = torch.Tensor(index)\n",
    "    assert t.ndim == index.ndim, \"t and index must have the same ndim\"\n",
    "    index = index.long()\n",
    "    return torch.gather(t, dim, index, **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0.6850],\n",
       "        [0.5206],\n",
       "        [0.0252],\n",
       "        [0.3718],\n",
       "        [0.7359]])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t = torch.rand(5, 3)\n",
    "index = torch.randint(0, 3, (5, 1))\n",
    "# index = [[0, 2], [0, 1], [1, 2], [0, 2], [0, 1]]\n",
    "torch_slice_by_dim(t, index)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def torch_nanmean(o, dim=None, keepdim=False):\n",
    "    \"\"\"There's currently no torch.nanmean function\"\"\"\n",
    "    mask = torch.isnan(o)\n",
    "    if mask.any():\n",
    "        output = torch.from_numpy(np.asarray(np.nanmean(o.cpu().numpy(), axis=dim, keepdims=keepdim))).to(o.device)\n",
    "        if output.shape == mask.shape:\n",
    "            output[mask] = 0\n",
    "        return output\n",
    "    else:\n",
    "        return torch.mean(o, dim=dim, keepdim=keepdim) if dim is not None else torch.mean(o)\n",
    "\n",
    "\n",
    "def torch_nanstd(o, dim=None, keepdim=False):\n",
    "    \"\"\"There's currently no torch.nanstd function\"\"\"\n",
    "    mask = torch.isnan(o)\n",
    "    if mask.any():\n",
    "        output = torch.from_numpy(np.asarray(np.nanstd(o.cpu().numpy(), axis=dim, keepdims=keepdim))).to(o.device)\n",
    "        if output.shape == mask.shape:\n",
    "            output[mask] = 1\n",
    "        return output\n",
    "    else:\n",
    "        return torch.std(o, dim=dim, keepdim=keepdim) if dim is not None else torch.std(o)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = torch.rand(1000)\n",
    "t[:100] = float('nan')\n",
    "assert torch_nanmean(t).item() > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def concat(*ls, dim=0):\n",
    "    \"Concatenate tensors, arrays, lists, or tuples by a dimension\"\n",
    "    if not len(ls): return []\n",
    "    it = ls[0]\n",
    "    if isinstance(it, torch.Tensor): return torch.cat(ls, dim=dim)\n",
    "    elif isinstance(it, np.ndarray): return np.concatenate(ls, axis=dim)\n",
    "    else:\n",
    "        res = np.concatenate(ls, axis=dim).tolist()\n",
    "        return retain_type(res, typ=type(it))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def reduce_memory_usage(df):\n",
    "    \n",
    "    start_memory = df.memory_usage().sum() / 1024**2\n",
    "    print(f\"Memory usage of dataframe is {start_memory} MB\")\n",
    "    \n",
    "    for col in df.columns:\n",
    "        col_type = df[col].dtype\n",
    "        \n",
    "        if col_type != 'object':\n",
    "            c_min = df[col].min()\n",
    "            c_max = df[col].max()\n",
    "            \n",
    "            if str(col_type)[:3] == 'int':\n",
    "                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n",
    "                    df[col] = df[col].astype(np.int8)\n",
    "                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n",
    "                    df[col] = df[col].astype(np.int16)\n",
    "                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:\n",
    "                    df[col] = df[col].astype(np.int32)\n",
    "                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:\n",
    "                    df[col] = df[col].astype(np.int64)\n",
    "            \n",
    "            else:\n",
    "                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:\n",
    "                    df[col] = df[col].astype(np.float16)\n",
    "                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:\n",
    "                    df[col] = df[col].astype(np.float32)\n",
    "                else:\n",
    "                    pass\n",
    "        else:\n",
    "            df[col] = df[col].astype('category')\n",
    "    \n",
    "    end_memory = df.memory_usage().sum() / 1024**2\n",
    "    print(f\"Memory usage of dataframe after reduction {end_memory} MB\")\n",
    "    print(f\"Reduced by {100 * (start_memory - end_memory) / start_memory} % \")\n",
    "    return df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def cls_name(o): return o.__class__.__name__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_eq(cls_name(timer), 'Timer')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def roll2d(o, roll1: Union[None, list, int] = None, roll2: Union[None, list, int] = None):\n",
    "    \"\"\"Rolls a 2D object on the indicated axis\n",
    "    This solution is based on https://stackoverflow.com/questions/20360675/roll-rows-of-a-matrix-independently\n",
    "    \"\"\"\n",
    "    \n",
    "    assert o.ndim == 2, \"roll2D can only be applied to 2d objects\"\n",
    "    axis1, axis2 = np.ogrid[:o.shape[0], :o.shape[1]]\n",
    "    if roll1 is not None:\n",
    "        if isinstance(roll1, int): axis1 = axis1 - np.array(roll1).reshape(1,1)\n",
    "        else: axis1 = np.array(roll1).reshape(o.shape[0],1)\n",
    "    if roll2:\n",
    "        if isinstance(roll2, int):  axis2 = axis2 - np.array(roll2).reshape(1,1)\n",
    "        else: axis2 = np.array(roll2).reshape(1,o.shape[1])\n",
    "    return o[axis1, axis2]\n",
    "\n",
    "\n",
    "def roll3d(o, roll1: Union[None, list, int] = None, roll2: Union[None, list, int] = None, roll3: Union[None, list, int] = None):\n",
    "    \"\"\"Rolls a 3D object on the indicated axis\n",
    "    This solution is based on https://stackoverflow.com/questions/20360675/roll-rows-of-a-matrix-independently\n",
    "    \"\"\"\n",
    "    \n",
    "    assert o.ndim == 3, \"roll3D can only be applied to 3d objects\"\n",
    "    axis1, axis2, axis3 = np.ogrid[:o.shape[0], :o.shape[1], :o.shape[2]]\n",
    "    if roll1 is not None:\n",
    "        if isinstance(roll1, int): axis1 = axis1 - np.array(roll1).reshape(1,1,1)\n",
    "        else: axis1 = np.array(roll1).reshape(o.shape[0],1,1)\n",
    "    if roll2:\n",
    "        if isinstance(roll2, int):  axis2 = axis2 - np.array(roll2).reshape(1,1,1)\n",
    "        else: axis2 = np.array(roll2).reshape(1,o.shape[1],1)\n",
    "    if roll3:\n",
    "        if isinstance(roll3, int):  axis3 = axis3 - np.array(roll3).reshape(1,1,1)\n",
    "        else: axis3 = np.array(roll3).reshape(1,1,o.shape[2])\n",
    "    return o[axis1, axis2, axis3]\n",
    "\n",
    "\n",
    "def random_roll2d(o, axis=()):\n",
    "    \"\"\"Rolls a 2D object on the indicated axis\n",
    "    This solution is based on https://stackoverflow.com/questions/20360675/roll-rows-of-a-matrix-independently\n",
    "    \"\"\"\n",
    "    \n",
    "    assert o.ndim == 2, \"roll2D can only be applied to 2d objects\"\n",
    "    axis1, axis2 = np.ogrid[:o.shape[0], :o.shape[1]]\n",
    "    if 0 in axis:\n",
    "        axis1 = np.random.choice(np.arange(o.shape[0]), o.shape[0], replace).reshape(-1, 1)\n",
    "    if 1 in axis:\n",
    "        axis2 = np.random.choice(np.arange(o.shape[1]), o.shape[1], replace).reshape(1, -1)\n",
    "    return o[axis1, axis2]\n",
    "\n",
    "\n",
    "def random_roll3d(o, axis=(), replace=False):\n",
    "    \"\"\"Randomly rolls a 3D object along the indicated axes\n",
    "    This solution is based on https://stackoverflow.com/questions/20360675/roll-rows-of-a-matrix-independently\n",
    "    \"\"\"\n",
    "    \n",
    "    assert o.ndim == 3, \"random_roll3d can only be applied to 3d objects\"\n",
    "    axis1, axis2, axis3 = np.ogrid[:o.shape[0], :o.shape[1], :o.shape[2]]\n",
    "    if 0 in axis:\n",
    "        axis1 = np.random.choice(np.arange(o.shape[0]), o.shape[0], replace).reshape(-1, 1, 1)\n",
    "    if 1 in axis:\n",
    "        axis2 = np.random.choice(np.arange(o.shape[1]), o.shape[1], replace).reshape(1, -1, 1)\n",
    "    if 2 in axis:\n",
    "        axis3 = np.random.choice(np.arange(o.shape[2]), o.shape[2], replace).reshape(1, 1, -1)\n",
    "    return o[axis1, axis2, axis3]\n",
    "\n",
    "def rotate_axis0(o, steps=1):\n",
    "    return o[np.arange(o.shape[0]) - steps]\n",
    "\n",
    "def rotate_axis1(o, steps=1):\n",
    "    return o[:, np.arange(o.shape[1]) - steps]\n",
    "\n",
    "def rotate_axis2(o, steps=1):\n",
    "    return o[:, :, np.arange(o.shape[2]) - steps]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  0,   1,   2,   3,   4,   5,   6,   7,   8,   9],\n",
       "       [  0,  10,  20,  30,  40,  50,  60,  70,  80,  90],\n",
       "       [  0, 100, 200, 300, 400, 500, 600, 700, 800, 900]])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.tile(np.arange(10), 3).reshape(3, 10) * np.array([1, 10, 100]).reshape(-1, 1)\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  0, 100, 200, 300, 400, 500, 600, 700, 800, 900],\n",
       "       [  0,  10,  20,  30,  40,  50,  60,  70,  80,  90],\n",
       "       [  0,   1,   2,   3,   4,   5,   6,   7,   8,   9]])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "roll2d(a, roll1=[2, 1, 0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  7,   8,   9,   0,   1,   2,   3,   4,   5,   6],\n",
       "       [ 70,  80,  90,   0,  10,  20,  30,  40,  50,  60],\n",
       "       [700, 800, 900,   0, 100, 200, 300, 400, 500, 600]])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "roll2d(a, roll2=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o = torch.arange(24).reshape(2,3,4)\n",
    "test_eq(rotate_axis0(o)[1], o[0])\n",
    "test_eq(rotate_axis1(o)[:,1], o[:,0])\n",
    "test_eq(rotate_axis2(o)[...,1], o[...,0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def chunks_calculator(shape, dtype='float32', n_bytes=1024**3):\n",
    "    \"\"\"Function to calculate chunks for a given size of n_bytes (default = 1024**3 == 1GB). \n",
    "    It guarantees > 50% of the chunk will be filled\"\"\"\n",
    "    \n",
    "    X  = np.random.rand(1, *shape[1:]).astype(dtype)\n",
    "    byts = get_size(X)\n",
    "    n = n_bytes // byts\n",
    "    if shape[0] / n <= 1: return False\n",
    "    remainder = shape[0] % n\n",
    "    if remainder / n < .5: \n",
    "        n_chunks = shape[0] // n\n",
    "        n += np.ceil(remainder / n_chunks).astype(int)\n",
    "    return (n, -1, -1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "shape = (1_000, 10, 1000)\n",
    "dtype = 'float32'\n",
    "test_eq(chunks_calculator(shape, dtype), False)\n",
    "\n",
    "shape = (54684, 10, 1000)\n",
    "dtype = 'float32'\n",
    "test_eq(chunks_calculator(shape, dtype), (27342, -1, -1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def is_memory_shared(a, b):\n",
    "    r\"\"\"Test function to check if 2 array-like object share memory. \n",
    "    Be careful because it changes their values!!!)\"\"\"\n",
    "    \n",
    "    try: \n",
    "        a[:] = 1\n",
    "    except: \n",
    "        try: \n",
    "            b[:] = 1\n",
    "        except: \n",
    "            print('unknown')\n",
    "            return \n",
    "    return torch.equal(tensor(a), tensor(b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.random.rand(2,3,4)\n",
    "t1 = torch.from_numpy(a)\n",
    "test_eq(is_memory_shared(a, t1), True)\n",
    "a = np.random.rand(2,3,4)\n",
    "t2 = torch.as_tensor(a)\n",
    "test_eq(is_memory_shared(a, t2), True)\n",
    "a = np.random.rand(2,3,4)\n",
    "t3 = torch.tensor(a)\n",
    "test_eq(is_memory_shared(a, t3), False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def assign_in_chunks(a, b, chunksize='auto', inplace=True, verbose=True):\n",
    "    \"\"\"Assigns values in b to an array-like object a using chunks to avoid memory overload.\n",
    "    \n",
    "    The resulting a retains it's dtype and share it's memory.\n",
    "    a: array-like object\n",
    "    b: may be an integer, float, str, 'rand' (for random data), or another array like object.\n",
    "    chunksize: is the size of chunks. If 'auto' chunks will have around 1GB each. \n",
    "    \"\"\"\n",
    "    \n",
    "    if b != 'rand' and not isinstance(b, (Iterable, Generator)):\n",
    "        a[:] = b\n",
    "    else:\n",
    "        shape = a.shape\n",
    "        dtype = a.dtype\n",
    "        if chunksize == \"auto\": \n",
    "            chunksize = chunks_calculator(shape, dtype)\n",
    "            chunksize = shape[0] if not chunksize else  chunksize[0]\n",
    "        for i in progress_bar(range((shape[0] - 1) // chunksize + 1), display=verbose, leave=False):\n",
    "            start, end = i * chunksize, min(shape[0], (i + 1) * chunksize)\n",
    "            if start >= shape[0]: break\n",
    "            if b == 'rand': \n",
    "                a[start:end] = np.random.rand(end - start, *shape[1:])\n",
    "            else: \n",
    "                a[start:end] = b[start:end]\n",
    "    if not inplace: return a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "a = np.random.rand(10,3,4).astype('float32')\n",
    "a_dtype = a.dtype\n",
    "a_id = id(a)\n",
    "b = np.random.rand(10,3,4).astype('float64')\n",
    "assign_in_chunks(a, b, chunksize=2, inplace=True, verbose=True)\n",
    "test_close(a, b)\n",
    "test_eq(a.dtype, a_dtype)\n",
    "test_eq(id(a), a_id)\n",
    "\n",
    "a = np.random.rand(10,3,4).astype('float32')\n",
    "a_dtype = a.dtype\n",
    "a_id = id(a)\n",
    "b = 1\n",
    "assign_in_chunks(a, b, chunksize=2, inplace=True, verbose=True)\n",
    "test_eq(a, np.ones_like(a).astype(a.dtype))\n",
    "test_eq(a.dtype, a_dtype)\n",
    "test_eq(id(a), a_id)\n",
    "\n",
    "a = np.random.rand(10,3,4).astype('float32')\n",
    "a_dtype = a.dtype\n",
    "a_id = id(a)\n",
    "b = 0.5\n",
    "assign_in_chunks(a, b, chunksize=2, inplace=True, verbose=True)\n",
    "test_eq(a.dtype, a_dtype)\n",
    "test_eq(id(a), a_id)\n",
    "\n",
    "a = np.random.rand(10,3,4).astype('float32')\n",
    "a_dtype = a.dtype\n",
    "a_id = id(a)\n",
    "b = 'rand'\n",
    "assign_in_chunks(a, b, chunksize=2, inplace=True, verbose=True)\n",
    "test_eq(a.dtype, a_dtype)\n",
    "test_eq(id(a), a_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "a = np.random.rand(10,3,4).astype('float32')\n",
    "b = np.random.rand(10,3,4).astype('float64')\n",
    "c = assign_in_chunks(a, b, chunksize=2, inplace=False, verbose=True)\n",
    "test_close(c, b)\n",
    "test_eq(a.dtype, c.dtype)\n",
    "test_eq(is_memory_shared(a, c), True)\n",
    "\n",
    "a = np.random.rand(10,3,4).astype('float32')\n",
    "b = 1\n",
    "c = assign_in_chunks(a, b, chunksize=2, inplace=False, verbose=True)\n",
    "test_eq(a, np.ones_like(a).astype(a.dtype))\n",
    "test_eq(a.dtype, c.dtype)\n",
    "test_eq(is_memory_shared(a, c), True)\n",
    "\n",
    "a = np.random.rand(10,3,4).astype('float32')\n",
    "b = 0.5\n",
    "c = assign_in_chunks(a, b, chunksize=2, inplace=False, verbose=True)\n",
    "test_eq(a.dtype, c.dtype)\n",
    "test_eq(is_memory_shared(a, c), True)\n",
    "\n",
    "a = np.random.rand(10,3,4).astype('float32')\n",
    "b = 'rand'\n",
    "c = assign_in_chunks(a, b, chunksize=2, inplace=False, verbose=True)\n",
    "test_eq(a.dtype, c.dtype)\n",
    "test_eq(is_memory_shared(a, c), True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def create_array(shape, fname=None, path='./data', on_disk=True, dtype='float32', mode='r+', fill_value='rand', chunksize='auto', verbose=True, **kwargs):\n",
    "    \"\"\"\n",
    "    mode:\n",
    "        ‘r’:  Open existing file for reading only.\n",
    "        ‘r+’: Open existing file for reading and writing.\n",
    "        ‘w+’: Create or overwrite existing file for reading and writing.\n",
    "        ‘c’:  Copy-on-write: assignments affect data in memory, but changes are not saved to disk. The file on disk is read-only.\n",
    "    fill_value: 'rand' (for random numbers), int or float\n",
    "    chunksize = 'auto' to calculate chunks of 1GB, or any integer (for a given number of samples)\n",
    "    \"\"\"\n",
    "    if on_disk:\n",
    "        assert fname is not None, 'you must provide a fname (filename)'\n",
    "        path = Path(path)\n",
    "        if not fname.endswith('npy'): fname = f'{fname}.npy'\n",
    "        filename = path/fname\n",
    "        filename.parent.mkdir(parents=True, exist_ok=True)\n",
    "        # Save a small empty array\n",
    "        _temp_fn = path/'temp_X.npy'\n",
    "        np.save(_temp_fn, np.empty(0))\n",
    "        # Create  & save file\n",
    "        arr = np.memmap(_temp_fn, dtype=dtype, mode='w+', shape=shape, **kwargs)\n",
    "        np.save(filename, arr)\n",
    "        del arr\n",
    "        os.remove(_temp_fn)\n",
    "        # Open file in selected mode\n",
    "        arr = np.load(filename, mmap_mode=mode)\n",
    "    else:\n",
    "        arr = np.empty(shape, dtype=dtype, **kwargs)\n",
    "    if fill_value != 0:\n",
    "        assign_in_chunks(arr, fill_value, chunksize=chunksize, inplace=True, verbose=verbose)\n",
    "    return arr\n",
    "\n",
    "create_empty_array = partial(create_array, fill_value=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fname = 'X_on_disk'\n",
    "shape = (100, 10, 10)\n",
    "X = create_array(shape, fname, on_disk=True, mode='r+')\n",
    "test_ne(abs(X).sum(), 0)\n",
    "os.remove(X.filename)\n",
    "del X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fname = 'X_on_disk'\n",
    "shape = (100, 10, 10)\n",
    "X = create_empty_array(shape, fname, on_disk=True, mode='r+')\n",
    "test_eq(abs(X).sum(), 0)\n",
    "\n",
    "chunksize = 10\n",
    "pbar = progress_bar(range(math.ceil(len(X) / chunksize)), leave=False)\n",
    "start = 0\n",
    "for i in pbar: \n",
    "    end = min(start + chunksize, len(X))\n",
    "    partial_data = np.random.rand(end - start, X.shape[1] , X.shape[2])\n",
    "    X[start:end] = partial_data\n",
    "    start = end\n",
    "    del partial_data\n",
    "    gc.collect()\n",
    "filename = X.filename\n",
    "del X\n",
    "X = np.load(filename, mmap_mode='r+')\n",
    "test_eq((X == 0).sum(), 0)\n",
    "test_eq(X.shape, shape)\n",
    "os.remove(X.filename)\n",
    "del X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "import gzip\n",
    "\n",
    "def np_save_compressed(arr, fname=None, path='./data', verbose=False, **kwargs):\n",
    "    assert fname is not None, 'you must provide a fname (filename)'\n",
    "    if fname.endswith('npy'): fname = f'{fname}.gz'\n",
    "    elif not fname.endswith('npy.gz'): fname = f'{fname}.npy.gz'\n",
    "    filename = Path(path)/fname\n",
    "    filename.parent.mkdir(parents=True, exist_ok=True)\n",
    "    f = gzip.GzipFile(filename, 'w', **kwargs)\n",
    "    np.save(file=f, arr=arr)\n",
    "    f.close()\n",
    "    pv(f'array saved to {filename}', verbose)\n",
    "    \n",
    "def np_load_compressed(fname=None, path='./data', **kwargs):\n",
    "    assert fname is not None, 'you must provide a fname (filename)'\n",
    "    if fname.endswith('npy'): fname = f'{fname}.gz'\n",
    "    elif not fname.endswith('npy.gz'): fname = f'{fname}.npy.gz'\n",
    "    filename = Path(path)/fname\n",
    "    f = gzip.GzipFile(filename, 'r', **kwargs)\n",
    "    arr = np.load(f)\n",
    "    f.close()\n",
    "    return arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X1 = np.random.rand(10)\n",
    "np_save_compressed(X1, 'X_comp', path='./data')\n",
    "X2 = np_load_compressed('X_comp')\n",
    "test_eq(X1, X2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def np2memmap(arr, fname=None, path='./data', dtype='float32', mode='c', **kwargs):\n",
    "    \"\"\" Function that turns an ndarray into a memmap ndarray\n",
    "    mode:\n",
    "        ‘r’:  Open existing file for reading only.\n",
    "        ‘r+’: Open existing file for reading and writing.\n",
    "        ‘w+’: Create or overwrite existing file for reading and writing.\n",
    "        ‘c’:  Copy-on-write: assignments affect data in memory, but changes are not saved to disk. The file on disk is read-only.\n",
    "    \"\"\"\n",
    "    assert fname is not None, 'you must provide a fname (filename)'\n",
    "    if not fname.endswith('npy'): fname = f'{fname}.npy'\n",
    "    filename = Path(path)/fname\n",
    "    filename.parent.mkdir(parents=True, exist_ok=True)\n",
    "    # Save file\n",
    "    np.save(filename, arr)\n",
    "    # Open file in selected mode\n",
    "    arr = np.load(filename, mmap_mode=mode)\n",
    "    return arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X1 = np.random.rand(10)\n",
    "X2 = np2memmap(X1, 'X1_test')\n",
    "test_eq(X1, X2)\n",
    "test_ne(type(X1), type(X2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export \n",
    "def torch_mean_groupby(o, idxs):\n",
    "    \"\"\"Computes torch mean along axis 0 grouped by the idxs. \n",
    "    Need to ensure that idxs have the same order as o\"\"\"\n",
    "    if is_listy(idxs[0]): idxs = flatten_list(idxs)\n",
    "    flattened_idxs = torch.tensor(idxs)\n",
    "    idxs, vals = torch.unique(flattened_idxs, return_counts=True)\n",
    "    vs = torch.split_with_sizes(o, tuple(vals))\n",
    "    return torch.cat([v.mean(0).unsqueeze(0) for k,v in zip(idxs, vs)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o = torch.arange(6*2*3).reshape(6, 2, 3).float()\n",
    "idxs = np.array([[0,1,2,3], [2,3]], dtype=object)\n",
    "output = torch_mean_groupby(o, idxs)\n",
    "test_eq(o[:2], output[:2])\n",
    "test_eq(o[2:4].mean(0), output[2])\n",
    "test_eq(o[4:6].mean(0), output[3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def torch_flip(t, dims=-1):\n",
    "    if dims == -1: return t[..., np.arange(t.shape[dims])[::-1].copy()]\n",
    "    elif dims == 0: return t[np.arange(t.shape[dims])[::-1].copy()]\n",
    "    elif dims == 1: return t[:, np.arange(t.shape[dims])[::-1].copy()]\n",
    "    elif dims == 2: return t[:, :, np.arange(t.shape[dims])[::-1].copy()]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = torch.randn(2, 3, 4)\n",
    "test_eq(torch.flip(t, (2,)), torch_flip(t, dims=-1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export \n",
    "def torch_nan_to_num(o, num=0, inplace=False):\n",
    "    mask = torch.isnan(o)\n",
    "    return torch_masked_to_num(o, mask, num=num, inplace=inplace)\n",
    "\n",
    "def torch_masked_to_num(o, mask, num=0, inplace=False):\n",
    "    if inplace: \n",
    "        o[:] = o.masked_fill(mask, num)\n",
    "    else: \n",
    "        return o.masked_fill(mask, num)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.rand(2, 4, 6)\n",
    "x[:, :3][x[:, :3] < .5] = np.nan\n",
    "nan_values = torch.isnan(x).sum()\n",
    "y = torch_nan_to_num(x[:, :3], inplace=False)\n",
    "test_eq(torch.isnan(y).sum(), 0)\n",
    "test_eq(torch.isnan(x).sum(), nan_values)\n",
    "torch_nan_to_num(x[:, :3], inplace=True)\n",
    "test_eq(torch.isnan(x).sum(), 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.rand(2, 4, 6)\n",
    "mask = x[:, :3] > .5\n",
    "x[:, :3] = torch_masked_to_num(x[:, :3], mask, num=0, inplace=False)\n",
    "test_eq(x[:, :3][mask].sum(), 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.rand(2, 4, 6)\n",
    "mask = x[:, :3] > .5\n",
    "torch_masked_to_num(x[:, :3], mask, num=0, inplace=True)\n",
    "test_eq(x[:, :3][mask].sum(), 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def mpl_trend(x, y, deg=1): \n",
    "    return np.poly1d(np.polyfit(x, y, deg))(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.sort(np.random.randint(0, 100, 100)/10)\n",
    "y = np.random.rand(100) + np.linspace(0, 10, 100)\n",
    "trend = mpl_trend(x, y)\n",
    "plt.scatter(x, y)\n",
    "plt.plot(x, trend, 'r')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def int2digits(o, n_digits=None, normalize=True):\n",
    "    if n_digits is not None:\n",
    "        iterable = '0' * (n_digits - len(str(abs(o)))) + str(abs(o))\n",
    "    else:\n",
    "        iterable = str(abs(o))\n",
    "    sign = np.sign(o)\n",
    "    digits = np.array([sign * int(d) for d in iterable])\n",
    "    if normalize:\n",
    "        digits = digits / 10\n",
    "    return digits\n",
    "\n",
    "\n",
    "def array2digits(o, n_digits=None, normalize=True):\n",
    "    output = np.array(list(map(partial(int2digits, n_digits=n_digits), o)))\n",
    "    if normalize:\n",
    "        output = output / 10\n",
    "    return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "o = -9645\n",
    "test_eq(int2digits(o, 6), np.array([ 0,  0, -.9, -.6, -.4, -.5]))\n",
    "\n",
    "a = np.random.randint(-1000, 1000, 10)\n",
    "test_eq(array2digits(a,5).shape, (10,5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def sincos_encoding(seq_len, device=None, to_np=False):\n",
    "    if to_np:\n",
    "        sin = np.sin(np.arange(seq_len) / seq_len * 2 * np.pi)\n",
    "        cos = np.cos(np.arange(seq_len) / seq_len * 2 * np.pi)\n",
    "    else:\n",
    "        if device is None: device = default_device()\n",
    "        sin = torch.sin(torch.arange(seq_len, device=device) / seq_len * 2 * np.pi)\n",
    "        cos = torch.cos(torch.arange(seq_len, device=device) / seq_len * 2 * np.pi)\n",
    "    return sin, cos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "sin, cos = sincos_encoding(100)\n",
    "plt.plot(sin.cpu().numpy())\n",
    "plt.plot(cos.cpu().numpy())\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def linear_encoding(seq_len, device=None, to_np=False, lin_range=(-1,1)):\n",
    "    if to_np:\n",
    "        enc =  np.linspace(lin_range[0], lin_range[1], seq_len)\n",
    "    else:\n",
    "        if device is None: device = default_device()\n",
    "        enc = torch.linspace(lin_range[0], lin_range[1], seq_len, device=device)\n",
    "    return enc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "lin = linear_encoding(100)\n",
    "plt.plot(lin.cpu().numpy())\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def encode_positions(pos_arr, min_val=None, max_val=None, linear=False, lin_range=(-1,1)):\n",
    "    \"\"\" Encodes an array with positions using a linear or sincos methods\n",
    "    \"\"\"\n",
    "    \n",
    "    if min_val is None:\n",
    "        min_val = np.nanmin(pos_arr)\n",
    "    if max_val is None:\n",
    "        max_val = np.nanmax(pos_arr)\n",
    "        \n",
    "    if linear: \n",
    "        return (((pos_arr - min_val)/(max_val - min_val)) * (lin_range[1] - lin_range[0]) + lin_range[0])\n",
    "    else:\n",
    "        sin = np.sin((pos_arr - min_val)/(max_val - min_val) * 2 * np.pi)\n",
    "        cos = np.cos((pos_arr - min_val)/(max_val - min_val) * 2 * np.pi)\n",
    "        return sin, cos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYwAAAD4CAYAAAD//dEpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAADkP0lEQVR4nOydZ3hcxdWA39lepJW06r0XS3LvvZuOTe+dQBJILx9JCElICCShBAKEHnqvxphiXHDvli3LsmT1Xne1vd/7/VjF2GAIxbYsvO/z7CPtlDtzVqt77sycImRZJkKECBEiRPhfKIZ6AhEiRIgQYXgQURgRIkSIEOErEVEYESJEiBDhKxFRGBEiRIgQ4SsRURgRIkSIEOEroRrqCXwTEhIS5JycnKGeRoQIESIMK3bs2NEny3LiN+0/LBVGTk4O27dvH+ppRIgQIcKwQgjR/G36R7akIkSIECHCVyKiMCJEiBAhwlciojAiRIgQIcJXIqIwIkSIECHCVyKiMCJEiBAhwlfiqCgMIcRTQogeIcTeL6gXQogHhBB1Qog9Qohxh9RdJYQ4MPi66mjMJ0KECBEiHH2O1grjaeDUL6k/DSgcfN0A/BtACGEG/gBMBiYBfxBCxB2lOUWIECFChKPIUfHDkGV5rRAi50uaLAaelcOx1DcLIWKFEKnAHGCFLMsWACHECsKK56UvG6/Z0sNv/vM3ypw9JCfEUDzmVDILRiHUuqMhzpDR5w+yZcCJtceFw+LBFZIISDIGfzPxoe0Y5f2EQh5CjiiwAX4VvlA6FpIRLiv4vaiR0CKh0+mIi4sjITkZ86hRRMfFYTQaMRqNCCGGWtQIEf4nfkmis7OGnoEeut1uun0+kgMWzigZT4+iFbe7FX8gCo97JF6vF5/PRygUIio9il51LwO+AVwOBzOMk8mVMwlavUieILpiM9ps02FjhQIS7Qes9HS76e514lVbGGg6gNTbBvZ+MrQS6TGxlN78E1Rm8xB9IkPP8XLcSwdaD3nfNlj2ReWfQwhxA+HVCaqiEfwn5xQANLKPMW07mbf5MRSNepSpY5m3+FxKUmNO6BujLMtsHHCy1eZid4+dvQ4PbYoj5CZRALok4HSEfCpm+kkydTMjfS2T2EgCHgzWVPZXzyCIjoOLRkmC/v7wa9++g5dLS0vj4osvxmQyfX6sCBGGGlnmk6r1PNJpY7MiCY9CA8QMvmC2tZuoyp8QUoVvGxZLGlV75x92iRiVkjHBPPL88URLWYCTfqoP1iuMahSpRprrrKxY14KtqRd1VwWKYC9yyIosDYDsO+ya+4DAdgvFl15xUisMcbQSKA2uMJbJslx+hLplwF2yLK8ffL8S+D/CKwydLMt/GSz/PeCRZfnuLxurdESJ/L0//B81Lj89Jj3b44sJoWA+KxjrqSBhwM7egSLcpotZOCqHs0alDrnykGWZVq+frTYXW20uNlud1HrCX8pMl0SxU6JUVjJRrcJrbmZvz1uUxexCq3Wye/9YmgLldBhzsBhN9JlisBhi0Yb8zB/YwNkxz6D2KuiuOhVv5wgIuonVduJX9dNjD6J0Wwlo1BgkgTUjh1iDkSUXX0R2JLxKhBMEV38zy2p2sqxngBUxY0n39XKa7wClcXEkJ+aRZIhCDlTTcuAfaFRW2ttn4VCU0KnpY5e3glm9ozjHOo8oyUBIJaPI1KOJN6BPiEYdb0AVp0PEaNj+cSvNVRb6251IgW5CvgpC/v1ACE1QYAgE0SakYk5LJS0rk4S8fOILCtGkpqLUaof6Y/rWCCF2yLI84Rv3P04K41FgjSzLLw2+ryGsLOYAc2RZvvFI7b6ICRMmyIeGBunw+LllzSes0MYjCwVa2ctcVlAyUMeWLaOYPOcMbjmt5KjI+U3YaHXyx/p29jg8AESFYJQ1yKzuIGcGVYgyJavitrGhbyMe2w6ujfeiUkh4+nW0fZKC0p5KR04uBrebjH4ro3JzaZ21mOfsEiujQRcKMYP1TFSspliuprNlFK4t3yNZt5vzYu5EjDqfj2qT2Vuxi4ApjmBiJpJSSbJSw+mXXUxmYeGQfTYRTmIkCSpeYP2OZfwx+Xz2RhcSF3LxQ4OdGybMRavR4XBU0dr2LL29HxEM2gkENNSHZvG8dQ/OoJMMTRq3tX+fzL4EVCNiMI1NRVdiRqFRHjKMxO69fWx+rwGp2U2bwokr2ECG7RNUcoAMq4NRYyaQNn8hhgkTUCUkDOGHcmwZLgrjDOBm4HTCB9wPyLI8afDQewfwX6upncD4/55pfBGfVRj/pd8fZPWGbbzc6mVTRgwhoaBAqmFkQzXT3Kmc/72r0BuO7znHdpuLs3ceIFWr5sb0RIreaKQgqCB6TCK7zLW8MvAW69vXoxMwR6tmUbwDnzWa5lVmVP54QupYelJSiVcquey004kbNxah+NRWoeJAL4/u72C5XsKnFBhkP9NZSWHLduI330RCSjvzpftJUBzAN+O3vLDOQf+BvQQTMpCM0SAEZ2XkMvIH1w/5KizCSUJXJWz/D+x/j2ejJ/Lrol9iIsg96RrOyC9DoVQiyzI1Nb+nveMlhNDg9YykvsHIflnLWtMGTs89nWtC5xO9JoDsCxF7bgFRk1I/N9Sa7R2se3Y/Zj8EZT99Ygex1k0A6H0BprT1UXD7nzGdfvrx/hSGhBNCYQghXiK8WkgAuglbPqkBZFl+RITvRA8SPtB2A9fIsrx9sO+1wG8HL3WHLMv/+V/jfZHC+C9yMMSapx9jvZTJ63lqupXJXCU9wYLa1cSW/IOJc4/Pl8MRDHHq9lq8ksTKsjz4pAPnxg5UF2fwoPNJlta/zcxoHTMVXhKNPlBKODuSaPwohuR+DfVjRqJSKJgwbRqz5s9Ho9F84Vj2Xjcfrq7nA7+H99I1JMud/MD5AMoti/FZCxhfsJlxAw+jvO5tdu/tYMf7S7EN2HDllZHT1ExBUEXRD64naebU4/LZRDhJCXjgnhII+aFgAWen/RCLOoaVk0rQDj4I+f39NDX/m9bW/+DxTGd3RTqybKTKVEV/aj+3Tr2V8d3FWF+rRZsXg2lhNtrcmMOG2bO/j5XLGwjVORDBHtTGfUh9+wj5faQMOCkxxJJ35VXEnHoqCr1+KD6JIeGEUBjHm/+lMACQJAIf3cXKj43cPmsUfXolv5X+QLqzk9SEuyifveSYzrHB7WPJrgP0+IM8rYph1JouJFcQzbh4LpV/jNXfzy3xQcw6NyFvFLaWcTjrfFhabeT2O9DMXMB2WeKGG24gLS3tK40pByTsq1p4bX8rt46K5hR5NRdIT7J95Q9ItI5Ap+7h6rTfopz9MwLjrmfdS8+yaVcFAXMyaq+XoppaNCNncNb/3YjCaDymn0+Ek5Stj8PyX8JV79KaOoXJm/bxk+xk/i8vlUDAzv6a39Hb+xGyHKSzo4iOjjmMGTOWHcYdvFT3Eu8seYd0dxI9D1WgzY4m4ZpyhOrTFfeeim5Wv1KLyhogJAdwq+rQDaxEIYVIsTpI7Rug5LobSPzB94fwQxg6Igrjf+Fz8NBLr3Nf6kj0QQd3Kn+E7FfTrHiQm86Ydky2YUKyzKnba2nz+vl7tZ+xDW40WdHELingRcvr3LPjHn6jm09y4rv07DmLnqpoZNdepICfxKRMLHmFWB0OsrOzueaaa772+J4aCz+paWVptEyW3MRPdDW8t7WJ6fsvwFD4Glc7XkQsfghp1CXs/OBdNq9ZhVVWEoqKIb+qkpLmLka/+yaa5OSj/tlEOAmRZah5H7b8GxrXQuYU+i9fxik7a7EGQrw/vohCg4bde76HxbKe3t6RNDelU1w8j4RxCbxU+xKftH3CRcUX8duxt9DzrwokX4jkH49FGa1BlmUaq/r54O0DhNrcOGQ7QltFlLUCv99LtMfHpA4rSaecQtwFF6AfM2aoP5EhI6IwviLPf7CWX2pNXLX/PRYVP0V/XzrNnqu45pyLSTAd3afplzr7+dn+Vu6o8nJKR4D4K8vQl5h5cOeDLF3/MdO7ZzNu5AfozE3UvDIWn9NJis2No6icLrOZ1NRUpk6dSmlpKSrVN7N89oYkXtnfyd+76vELwcqCfN54YDt+f4C2wv/wT40d5Y1rgUELrn2VvPjyK/hkOHXpcqLVKhIuvRjzNdec1GaEEb4lzh748HdQ+SqYMmDitWwrvYZf1ffQ6PHx9thCxpoMNLc8QV3dnXg957Bjh4mc2Tm8NfAWdQN1mHVmLiy+kGtLrsH9RjOevX0kfm8U2rwYJEnmnX9V0FFtxU0Qt76euIE1BD1ukm0u8tUGii6+lJizzkIZHT3Un8aQE1EYX5FASKJkVQWzOz3M77ydpHEN+PxGduw6jZisSdxw/ikYDIZvPTd7MMTMLdUk9ft5rkUQf34R6hQjG5s3s/zBSlIdeWRMvZeozP10bE3EtyEKoymRlqISfEIwe/Zspk+f/o0VxWdZU/0RF3clsdDSw59TS3nvlWpCfhlF4itcc8lFGEcsOth208oVfLhuA6Kvh9TWHqbV7cdQVETuKy8jvuT8JEKEI+K1wXPnQEcFzPwFzP4/VlhdXL23EbNaxYMjspltjsZu38P2HRcSCpayYcNI0ssyeMD9AMVxxVxeejmn5Z6GckCi79l9BLvdmE7NIXp2Bu01Vj5+/QCuNhfbNP2Ml1fi72kjPjGF8rVbMWfnkPXsM6jiIsEj/ktEYXwNzlu7izqnxItbOqnovZ/kcxsJBVXs2bsQjyeZKZMnMWPGjG+sOCyBINfvbWLzgJP/bHIxfX4eUZNTWbd3C++/sItUSwFZKfcRNXs/XduSSX/DR/JV1/JKby/Z2dksXLiQjIyMbzT2FyFJfn669k5elReT5Avyp/gkDry7DmNPKj71AGfnraPg/EsgcxIAzzzxOI1t7ajsFnS9PSzaUUnWHXcQe86SozqvCN9x9rwaPqvw2uCCp6HsHFzBEPO316BTKHh3XCFRSgUtrU/S1PQwHo/E9m2noc9M4B31O8QaYnnz7DfBHsSxqhXX9m6ESoH5omKkjCjee7SS3gY7TtmBg22YHXtRKpXMGDWBqKXLUSiU5H/4AQrd8I7+cLT5tgrjpIpWe3VxDt16JW+lJRKTuQDVI0lIPigrXEV/QMXGjRu5//77WbNmDT6f739f8DM83trLxgEnv2mXKLNL6ApiWblmK7sespFoTUYZcx+6KbUEXSpKX7KRMXIsW4xGlEolF1100VFXFgAKhYY/jz2L33EXBnUXN9v7CV0yC9M5fdg1Dj6sOZ0N9z2P9+nLoH0nl119DXPnziVoMuPKzGFjWR5N7y096vOK8B1m98vw5g2QVAY3fAJl5/BBr41Jm6tp8vj5fX4a0Solff2rqKu7E5czgco988iZUsbTPE1xQjH3zbkP99pOuv6xHdeOboyTU0j5xXikjCiW3l9BV0MPDf5VKB3/weyopGzqDOY7JQxPPos2K5uMhx6KKItjwEm1wpBlmav31PFRv5M/V3oxeteSXP8m8sV9WBti2G+5jvxMMzU1NZhMJr7//e9/rdXG6VtrCHY6eaY6RMxpuWxqb2H/UhuWqE4MvMjIBbUo7ILkV82kX/hz1igU7Nm7l4ULFzJ9+vSvLc/Xob9/LRt3/5DnfLewVlfO/0WbeGf/9ZzefjXGxnS0Cjfjja8xcvE0VDO+T03tAV588UWUXjfGpmqu+OXvSZow8ZjOMcJ3gPX/hI//ANkz4LLXcCq03N/czSOtvYyI0nFXYQbjYoz4/X7Wrb8Mv38f27ddQM6EfJ5xPoNOpeOdxe+AR6Lzr1vQFcQSe04hqlgtXY02lt5fgc9rpdv1LrGBXspnzqE4IPA//yKyz0faPXcTvXBhxKfoC4isML4GQggeKc9ncmwUt47SszxjFg/MSqV32yLi8mzkqZ6ma+1Kzpg7B4fDwYcffshXVai9nQ52O91M7AuRcHUZqqI49r3fT4epnlXGLspmH0DhF6TcqyD7htvZHBXFnr17mTFjxjFXFgDx8bMYmXcz39f9lTKpiud6+7jQeCZLsx/jgt9OILk4jY2Oq3nhlUT62pwUFxUydv7ZBLV63JmFfPzAl0ZriRAh7Lm99XHImARXvEkfGi7eXc+/WnpYnBTLa6PzGRdjpLKykgce+CfB4B6k0GgyTsnm7z1/J1oTzV9n/BWFJBh4tx5CMqZFOShMGja+Wcdbd+/EEbBis71ATMjC/O/9hLK9dXgfeQzDpEnkvv0WpkWLIsriGHJSKQwAvVLBC6PzuCnKxJoUHdtTf8dL0YsYqJ1A8kgLuqhmNj31EONHj2L37t1s2LDhf14z5PTzxvs1hIRgyZw81ClG1qzbhSKgoiF9M7+e+DRCKWP8tw5T+Uy0M2eya9cuRowYwbx5846D1GFycr7PlMnLmaPaQodOQ1r3ePxuLzulTZz1k/GcvagVORTinXu307rfwtnTx9BqKiNkjKYpysTeFe8ft7lGGIbsfhHsbTDpe3xs8zF9SzUVDjdPlOXwYGk20UoFmzdv5o033iAhMYBKFSQqdzT3Vd/H/Kz5vHbWa5QbR2B5tQZPRS9R09NQpxmp3tDBro9aGIiTsNjexKCGC844j6g/3Y5z9WqSb/s9mQ8/hDY/f6g/ge88J53CADAqldw6Ppe3a2VmWgVbRuTyZvD7SHYjRYsaCOqCtK14l9LSUj7++GO6u7u/9HqO1a0sjRVkqlRMyIsnEAyyeUUNLl03VxZvRch+3CuSiG0MkPTrX1FdU0MgEGDSpEkoFMf3T2Aw5HBu3lwANmZs4W7rtdy+7k9U9VeROW8eZ8f/BZXsZN0rBxACbrvyNAKSDn9SOu+9+hJuu+24zjfCMGHTQ/DOTZAzk77Cs/hVTSspWjUrJ5ZwZlIswWCQZ555hg8++ICCggLmzcsD4LHaj8mLyePOmXfir7TSdc92PJV9mE7NIfasfGw9Hja+WU/QrKKj7Q3MQSszQio8f74DVWIiOa+8jPnSS4dY+JOHk1JhAAiFYOTiIu6tk5hpCbGmxMRbTX8EAZlZXbj6eihOMqPValm5cuUXXsff7mR1fR8745R8LycJS6eLJ//8MfGONExlz6HRuHGvN1HcGIcmPx9HXByrV68mOTmZ7Ozs4yfwIZRmLCFL7WOvMZHgqAf4hcjlyuWXUeHvxzxlERM1T2PtdNFZbyM3MYo//v6XqP1BfHFJvHjNjfTYvUMy7wgnKJ17YNUdULiI9ac/zawddfT5g9xdnEmxMXzw/P7779Pc3MzZZ5/NZZddhtOxC0lhYI+tk59P+DnyXgeWl/ejMutJ+tFYTHMy8XuDLP/3HgR+urtfJsfTwhivTExtPSl/+hM5r76CfvToIRb+5OKkVRgAmrQo4s4t5He7PeT74f2yHDracjBP6sFQ4uGDV19n8pRp1NbW0tDQ8Ln+rp3d9Dy0i1czVCQolVyebOa1f27C2e+jbezDFObX0FcZy4LMaYj99cRdcw0vv/wyfr+fM84447ivLv6LEIKZCansZCzV4hJi07ZwWwI8uf13WMZcQqF2LWpViKp17QCo1Srmnnk6kiEKhz7E/X98lB5HRGmc9IQC8PGf4LE5oDHCaX/jzy39RCmVrJhYxMSYsEPszp072bFjBzNmzGDcuHCc0c6+1VS6/ExMmcREz0gsL9egyYwm4fqRaNKicNl8vP9IJdYuC15pOWZHC6WdVjJau8h48EHiLroQoVR+yeQiHAtOaoUBoCuKI3tMMrft8uJTC/6S8Df290+iaHYTueVbWV7RTpzZzFtvvYXL5TrYz7WrB+ubB3Dlm1gbr2RxspF7XnyYkF3Jx5mrOD2tgpBVg695FM5WPcqYGGrTUunv7+fss88mKytrCKWG/8tNpdCg5dXoi8hqu4UYVJyt3c+/d11DS8l0SrQrqN3SxfrXDhD0h5g4cSIGnQ5bbjGxPZv5/gPL8QZCQypDhCFEkuDD38L6e2H0JXDTFrYoktjt8PC9jERKjOGAfi0tLbz33nvk5eUdPK9zuQ5A0EJLwMA9s+/BsaoFZayWxBtGodAqcVi8vHT7FjrrbIiYnXg7axnV1kNZ2Wjylr+HcfKkoZT8pOakVxgAsUsKmDA6lce3uRFKiX8Zf4FYYya+xMYo3YNsDabgdrt58803kSQJWZKxvdeAOjWKXQvSCAFba+/GX2XAonFQahqN3yhjb00gJjEb+9q17J8/jw9XrKCwsJCSkqHLzfFfkrRqvpeRSI3bS9uEs8jb8FfieuczxeBieXKAqTmbGGn8kN0rW3nljm30t7m59vrr0QOerBym7H2Wvz729lCLEWEoGGiBZ8+GrY/B5O/DkofYHtBy3d4mMnUaLk41EwqFWLNmDU8//TTR0dGcd955KBQKJClIQ+P9BGRBVOxMYpUm/M0ODGOSECoFkiSz+Z16At4QM6/OwNuwmfQBB8VjJ5P58EOoI/HNhpSIwiB8nhFzag6jnTJ/8hsZiFJxR94D2HdmkFbUzelx99FiKKK+vp5XX30VW30PkjNA1LQ0PnY4MeClcFsaKY48mgxR3JT9FgB9DRrE6k+oTU1hp0ZDeXk555133glj9ndechzZOg2/HOhHe+V40huuQztQTI5UQ/fM85gV/ShnXyQIBkK8+fcdNG5xcMHpZyCr1ATS84ha/wLPvbFiqMWIcDw58DE8PC0c7uPsB+HUu5BkmV/WtKJTCp4flYdvwMqTTz7JmjVrKCsr48Ybb8Q4GP24vuEf9PZ+wMd2FUWJE/B3uECS0WRE4fMEefvendRu6SZ2TDxv3XsbApm08bPIeuCfJ8z/zclMRGEMIlQKNJnRzG7184PEaKqy9bymuhNLVRrJGT20dbYip42itraWx158ija1leY0wXu9VjJauijtmcoOg4Pvz/wDTbp9+DsNuHq0pMcl0DF3LqmpqZx33nnoTiDvU6NKyb/Lsun2B3hYeIm/spTU/ddg9Mey3/4yslCQKW/gkt9PJm9sElvfbSS+YDTnLl6MZIwmmJJJ86uPcevblV/ZXyXCMGfV7RCdDD/YAOOuACF4ucvCfpeXW3JTSQ35efLJJ7FarVxwwQWcd9556AfzTfh8vTS3PsNOt4aNXjNzMufgb7EDIFIMrHx6H10NdtIWpXN7dS36oJ1cp49Zf/lj5LziBCGiMA5Blx9LsM3Jzwa0LIqPZtMIDb0dVyKUcHnqq+zZuY94xQQ0qPhQtYtrNm0BKcSpFbHsjYWzJj6MXddB//ZEqpdmMiE5l56rrqGrv58xJ2hI5XEmI5Njothic6HJiCZx9lRSDlyICPZSPTaP0PbH0AR6mX5+AQC1W7sZOX488xYuxB8Th1qvpHLZBzy/pWWIJYlwzOmthc7dMOE6iAtb+PkkidvrOpgaa+Sc5DjWrl1LIBDguuuuo6ys7GBXWZZZs/M6glKANvVo3jz7TdKVqTjWtCKSDLz54B4a9/Qx9swcntm0lb/tfAQEZM9bEFEWJxBHRWEIIU4VQtQIIeqEELccof4+IUTF4KtWCDFwSF3okLohDVoUNSsD3Qgz9uVN3GyIwaNRsSqzEFdNOcmj+5kbXEdVdyOXzToPr1bLvMoKrt3RRqwEqpgPMZnrsNbF0LsphrmxaYy69Y9s276dMWPGMHHiiRtWY2S0nmqXh4Ako02NJrprEpV9KXREDVCdJcOmB4k260gvjmPf+g5CIYmJkyah12oJxiVxdtdHvPzmBnzByCH4d5qtj4FSA+XnHSxaY3EwEAzxo6xkFMCBAwcoKCgg4ZC82LIss2r3r1B5qqgI5XLvwhdIMabg2tSB5AqypsmBzx3krB+NZufKN/jj8n+g1IS/S/nXXHu8pYzwJXxrhSGEUAIPAacBpcAlQojSQ9vIsvwzWZbHyLI8BvgX8OYh1Z7/1smyfPa3nc+3QaFRYr6gCIVRTfayZi5JMbOhNJa3/TcjZEFGaQ/5Pe/zz4o3eX3UTJSSwGhtoyVzM+dMfAOfW01gjZFzz7qYonvv55kXXkChUDB79uwhM6H9KoyKNuCTZGpcHlTJBgQKcv03ssquojtRg6PqSdj/HmMWZOK0+lj1TDVCVjJy9GhCsfFYo/VcuvNJbntkBQ5vYKjFiXAscFug4gUYeUF4Swro9gW4pbaNBLWKmXHR9Pb2YrPZyMvLO6xrR+erYHmLumAM35/1GkqFEs/ePuyrWumRZDSpRi7+/SS6t65i3ntP0ltcQnNmMin5hUTHJw6FtBG+gKNxF5sE1Mmy3CDLsh94GVj8Je0vAV46CuMeExQGNbFn5hHocvOHkJ5CTZDNOVFYG2cSM8pObIqb2M2fMKJ+B9GONPzafsqjN+B3qOl4Po35sy4n9dpr+OCDD7Db7Vx55ZXEneDx+KfGGtEpBH9t6CSoV6I0aZjYVUKNMw2XrGT7yCi8H/+a7BExTDorl9pt3bz+t+1kpeYjyTIxRSPpiteTtPIJvvfUJiQpcp7xnWP7kxBww9SbDha92ztApy/A0yNzCfl9LFu2DI1Gw4gRIw628Xo7qdz/B+q8CrIK/kysLo6QK0DfqzUMBCSqFQoWXluGOuhCPHA3deYs6pP1KFRqTv3hzyMH3ScYR0NhpAOth7xvGyz7HEKIbCAXWHVIsU4IsV0IsVkIseSLBhFC3DDYbntvb+9RmPYXoy9PQBmrxbeylTOSk7FE66itXURgIJGcs5pJHtfP7PUryNRFkatspKF7FF17EhlPLInXX0dDQwOVlZXMnDlzyP0tvgqpWg235aexyuJgyc46POfkIfX7+LPuLzxpjccrZHZkOfFWPMrEM3I560ejcdv8bHimk9SEDLrVelJSc0DtoWztQ9z63JrIIfh3iYFWWHcvFJ8OyZ+eS2ywOsnSacj0Onnsscdoa2vjzDPPJPqQzHZr994KcgAp8XJOzT0dANvaNoRfojFaw7m/m0RssoGtv7oNrcdJ5+KzcVn6WXjDj4jPyDzuokb4co73PsnFwOuyLB+62Z09GG73UuCfQogjRhCTZfkxWZYnyLI8ITHx2C5ThVIQc0YugU4X5a1+EII1Be00rP4D2ho96RO7yV3Ugr73GeIyapAkNVbHeAoefAihVlNRUYFer2fmzJnHdJ5Hk2szEnmiLIcDbi/nW3tQjDATu0/BfTOe4zmLEZtBxRbLvVirHiGrNJ4LfzeR+NQo/PsyMJsSOBCbQHxiDtFBB9HvP8Bzb3481CJFOFpUvhpeXZzy14NF7pDEequDkYoQTzzxBH6/n6uuuopRo0YdbGPz2ei3rKdLiuGG8bcihMCzrx/HunZ6ghLTritHp1ew45Y/Erf+Y9ZNPA25aRsJWTnkjf3GEbgjHEOOhsJoBw59FMgYLDsSF/OZ7ShZltsHfzYAa4CxR2FO3xp9eQJKk4aidd2keSX2Fs6kX6ejqvMqUjcHiMl14k3rwRTVS4pciTM6jpeXLcNms1FbW0tRUdFRS7N6vDgzKZZHy3Lo8AVYP8mM5A0SvdzDtaPv5oFeE32ygt2NdyFvfIhos45zfjGOmFgTyf4JTJw4kabERGKNiRhCIeqWvhDZmvquUL0M0saBOfdg0dvdVhwhCeOOzZjNZm688cbDYqNJssQ9W/5AkipIWca5KBVK/K0O+p7dh90fIjQxlfj0KCr/ejeGt19hTels8qZm4rT2s/B7NyFO4DO/k5mj8VfZBhQKIXKFEBrCSuFz1k5CiBIgDth0SFmcEEI7+HsCMB3YdxTm9K0RQqDJjcHgDvGSwYxCoeL9cQKHM4cRfhueDgNx42yIJ6KY7ytg8ZIltLe38+CDDxIMBk9oq6gvY645mly9hufdTuKWFOKrt1G+zMz9k55nsy+BkEHJjn1/gf56lCoFo+dn0lVnR9WZTXl5OZ15eeR19RLj7ePJ979+kqsIJxj734OOnTDqwoNFrmCIfzR1kSdCxPW0s3jx4sO2oQCe2vsUWN9HBkZkXgBA70dNhGSZ6mgtY8/J540NB3C//joVWaPIvWA2VWtWMP70xaQVjSDCicm3VhiyLAeBm4EPgWrgVVmWq4QQtwshDrV6uhh4WT58c3sEsF0IsRtYDdwly/IJoTAAhDb88aTqtRiVShpTTfhFHD3BQoq6BlAbgzgKlSRMnkJ6ejoKhYJAIEBycvJhZoXDCYUQXJmWwFabi4YRJhKuK0dyBYhZ6uXXc97ggFeJLc9A3a6fIsshRs3LYMqSPOq292AIJOOTZVRTZyBkmYaX/sX6igNDLVKEb0rFS/Da1ZBcHva9GOSlLgudvgDT6yrJyc4mLS3tc113dnzCjKgQaakXEhVVjK3WinRggA4hOPMX4/jHylo8v/klJr+bOb/7ES3rPiKrfBSzr7juc9eKcOJwVNZ9siwvl2W5SJblfFmW7xgsu02W5aWHtPmjLMu3fKbfRlmWR8qyPHrw55NHYz5Hi2CvBwRUbu/AEZCRhYLt+YI3+/+M3DcCv0WD8hQXa19/gHdefRWVSsWiRYtob29ny5YtQz39b8wlqWbiVEr+UNeBNi+GuHMLCXa7MR5QsUczlwqnhmbFPlqan0AIwfhTc0jNj6F3nyA1JZUtBiOJGDAHBlh79630trX+70EjnFh0VcI7P4TMyXDVu6DSANDnD/JkWy/lejXGtiZGjhz5ua6SJJHqr0ApZLIyr0GWZbpe3E9Alkk6v5Afv7GH1z/YxfieWkw33sDmzStx9Pcy9rTFEauoE5zIRuEXEHL68TfbceRGk93i5uEtPWT0OtlaJGiP7WLlwK8YXedHqZIQZ/ZgWPUxS5YsYdq0aaSnp1NbWzvUInxjYtUqfpOXysYBJ+/0DKAri0eVoMe1pZPpqbN42qoiyuKnof4eLJZwRsLxp+Xg6g8Q1T2SosJi6kvLyAmqUQa9vPXsC0MsUYSvhSzD8l+DPg4ufBYM5sFimR/sa6LTF2CJL5xIq6io6HPdt1T+iGlGNz7DRKKiirDv7cfoDdKbGsXN62tZtb+bv8Z0EFAIPm6sorFiBwuu/yEFEyYfVzEjfH0iCuMLsK9oBgQVc1L4c5mWsXY9Nzd7kVQmXpymQkKwz3Utuc1ujMleQlF9pLeGn6SLiopob2+nr69vaIX4FlyWFk+JUcdDLT0IIYiamY6/xcG0TQVoJQ19yiloPX7qq34PQHZ5PGfePIqBTi8lidPISk3lQFExuoAK296tdNVHtqaGDbUfQstGmH/bYcrirsYu1lmd/DY7CfeW9eTk5GAymQ7rurXucdz9H7DRbWRs+X3IskzzB01Issyd9gHaBzy8nNRG1mtP0Td2JP3dnZz9i98xeuHpQyFphK9JRGEcAckdwLWjG+PEZLaHHCxNg2qpnwX9Ws7r34LbWEZLfDut/hlYe1JAAuUYDzvv/AtBi4Xx48ej0Wj46KOPhlqUb4xSCK5Mi6fS6WGX3U3U5FRiz8pDXe/nrtaf8rEpjRRnFPZAM76OzQBklcZjStDR3WBn3imn4NdqyPZ58ctKlj14b8Q3Y7iw8xmISoYxlx8suqOhk/ubu7ks1czY/k7cbjfz588/rNue9g+xNN9FX0jDFTPeIFmfzIan96HvddOnVVLh9vDYxaMwPfcYiimTaYyPJjEnL7KyGEZEFMYRcO3sgaBMcHwSK3ttpFpl/COfwmdo45w9OQhZ5s1pqdgdIR6030Koz0h80QC1GRo677+fqKgoZs2aRW1tLZWVlUMtzjfm/BQzZrWSP9W145ckoqanE7u4gBJ3Dr01bWzLXQJAX91/DvZJzY+ls36A9NQMzHFx1JSPJMURwNbRSlv13iGSJMJXxmuDAx+FraKUYbPwJo+PR1p7uDjFzN3FmTTW1xEdHU1GRsZhXdftuwMBzJn8Djmxhax9ZA/J1f1oVAr+GnJx+sgURlka8fm8rFZ4cdlszL3y+iEQMsI3JaIwPoPkDeJY3Yom18TtzgF6ggrm1PVjTN1HC2spCpj4ia8LpyGJNWV+JjvNLGv+CQqVTNYFbazfv4rel15iypQpZGRk8Oabb2K1WodarG+ESaXktvw0NttcXL6nAXdIwjg+CaFTctPApTxRtxGdV6bTt+Pg6qFgQhIeZ4CVT1dz4UUX4dfr0cQYCaDmrX/8Bb/HPcRSRfhSGj4BKRj26h7k4347QRl+npNMU1MTtbW1FBYWHnZA3dCxjFzRjldbQrKpiP6dPWS32FFrlfza4KfVqOC3p4/A9u4yeswxuJwOzvn178ksG3WkWUQ4QYkojM9gX9mC5ApgWZjBa91WJtVYmal+GRTQ2GYB4Ka4MaS5WtlcbMKbHmREdwGvb7sAjT6IYoabZc8/QffDD3HBBRcgyzIVFRVDK9S34OLUeO4tyWSt1ckb3RaEWkncOQVkOJO4tfZ77HfGY1NaaWp6EICckQlMPiuX+l29SA4tJaWltObmMqLdQsDtoqVq+K64vvMEPOGItFoTZHzqR7TD5iJVqyZLr+Xjjz8mOjr6YLpVAIdzPw37f0ZfUFBQ+DuC/iADbx3AL0HDogy2OD386exyTNvWY3v7bWylxRhj48go/byFVYQTm4jCOAT3nl6c69oxTkzhbfwIWWZag4eo8o1Y60xsCqXj0yjo2FjPjKoaUGh4dLySgCdEs30OaoeZxMIBnEkq3vt4Gd7NmygoKGD9+vW0tg5f09JLUsyka9WssTgAMIxOIvHqcrJDqYyqvAWLQ0NL63+QJD8AoxdkYYzVsuH1OiZNnIRfpSKQFI+QoW7b5qEUJcIXIYXghQugaT0s+jMo1QA4giE221yMNxno6emhvb2diRMnEhUVdbBrVcO/CckSb7hyKEmczI77K9AGJByl8fxm3QESo7VMattD+09/hhhVTrvbTt64iRET2mFIRGEcgne/BUWUGvVZuTzb1kNBh4c0/bso1DKVjaOpKTiV/mQvxl7B1cpR/DJdiV2fQHVWgPmSmrvrr0GhhFHnNxBMhHcffYAzxo1DpVKxc+fOoRbvGyOEYLY5mnVWB35JAkBXFEfajeNJCpmhfSHBoI2WlicAUGuUTD47j55mB75eLbm5uTSMGUvygJPq1StwDQzPLbrvNLueg6Z1cNY/YfzVANgCQc7bVUevP8AlKWZWrVqFWq0+LF5UR996LD3vUes3ct/8x2hd00FSnxt/jJZtOVq67T6eumoitiefQJObS+vc6UihIBMXnz80ckb4VkQUxiEEulwo04z8cHctlpDMrL1uTBmbCXoVvBw8g6uybCzvWUdPmo+kPj0/jC8mRgnri23oHVDQUkhI/jVCFWLEeS3Y9bDnxzeRnZhIQ0PDsLYSOj0xFntQYvXgKgNAkxmNaXY2U1rOY8CSQX3DPdTX34MsyxRPSSEhM4o1z9eQFJuBWwoRKJ4Cssyrv/05oWBwCKWJcBjNm+C9X0DWNBh31cHiFzst7HF6eKo8F7FnB/v372fWrFkHVxfBkJ/te36EQ4I5Yx4k15RLYFULISEwXlbEi9taGJ8dR6G7G29lJeLURVR+spJRC04lLuXz3uERTnwiCmMQOSQT6HGzNUnNR04/s/fYmSF+jyHPSVtHOotytbQeqGLGzBmUnRc2A5TbnCxIiMNrzuaTvFfIDyp5ZW0Rhap5SLogerMPu1ZN7PLl2Gw2Vq9ePWyVxuy4aOLVKp5pP9y3JHZhLoqRRiZtv51GSxJNzQ9Te+B2FArBmTePJjpeR90qDwCmRfNItASw9PfSunH9UIgR4bPIMnx0a9iM9tKXYXCbyCdJvNJlYUy0gXEE2LBhA+Xl5cyYMeNg1+V7/4oRO27T6YxMnYV1Ywf6oIS7KI7fra6j1+Hjl4uK6fvXgwijkQpbDyqNlinnXjxU0kb4lkQUxiD+ZhsEZZ4MWdD6JW7ceAeahT3YOkz8p+PH5PqbSExMZN68eWhSohBqBf5WB2NNBhyyltacdhwGC9E2HxXBcFjzmFQJ1fx55Byoo0SlYu3atWzbtm2IJf1mqBWCGzMTWWVxsKxn4GC5UAjSLhmP0CqJq13MBoeKtrZncTprMMZoOecX40hMTEQbiuPAvgren345yDI1zz8zdMJE+JSuSmjfDjN+BroYIBy6/OrKRva7vNyQHs9zzz2HVqtlwYIFB88dfCEfbR1v4JbVXDXpXgJ9HlwfNzMQlKhK0fBxdTc/mlfIGHcHthUrqJo6lsbKCqZfeBnG2BM7oViELyaiMAib0g4sa+DJEh2bTQbGNfWhOLWegFvJ+9tP59bZqdgHLMybNw+FQoFQhiPZurZ2UR5+eObcUb+lNWYfmSG4ZYMSZUjGmODB4/OgLx3BlJpacnJyWLNmDX6/f2gF/oZcn5HIOJOBG/c18V7vwMFyoRDoC8xM8Y1lnVWJhKCz8w0AdEY1cy4rwWDNI+ANUqzrJKCMprWjFU9lxC9jSJFl2PYEKFQH83RLssyVexpYY3Fwb3Emo1xWbDYbZ555JrGxsQe7PrHnUXLVbmLMcwn1+uh9dDdySGanO8Qd6+qZmhfPdTNy6bn3XjoyUmjq7WTGxVcy/owlQyNrhKNCRGEAA8sa2OX28u9sNeXNbn6o+xXBDJm2dalMmnsq+3ZsIj09nZKSkoN9zBcUIXRKMla1o1MIHMpszpozD7WkITt6GwqXGn3CAM6+LvQjR+GtqmLWjBm43e5hG2fKoFTw6uh8yqP0/F9NG67Qp3mwdKXxyD4DF/UWs8etpqX1Sfr6VgOQkhvDjDNHEt07EqUUxJlfis2oo/r7N+Ldd8IEJz65kGVY+aewV/eEaw+GAFnaM8D6ASd3FWVwaVo8VVVVaLXaw2JGPVH5BEurH0WjgDz9PHof2wMIWrJMDKgV+BVw94Wjcb/yMl27dlKTEkdqUQmTllwwRMJGOFqc9AojaPXi3tnNByOiUIZklgzciSLTSeUnJfRbC5henIDdbmf27NmHmQEqozWYFmZDo4MxXsE6q4OFM6YhdBKlfUW83VuCMjaArNmHvigD2e0myWYjKiqKbdu2EQqFvmRWJy5RKiV/KkinLxDk3UO2pgxjElHFqjjFeg4fWk30BVVUH7gDWQ5bVY2cnYFWRJMaXYRKJRHQGdiZEE3jT3+GHAgMkTQnKbIMH/wG1t8H46+BU/92sOq1LivZOg1XpMUjyzINDQ3k5eWhUqmQZZmHKh7i/p33c0ZaOFVr4G0VQq0k6cZRdA/46ZVDLChNIkUVoum+e9hakoU6KprTfviziBntd4CTXmG4d/dSYVLyelSQoo4AJVnVKOrVBA8omDpnFtX7qtDr9eTnfz5zrHFiCtHzsxjf5KHa5aU3GGLKmQVk2kYgN0/D4zISP7YfTdczCK0W5/L3mTNnDs3NzWzatOkIsxkeTI4xEq9Wsd7qPFgmlApMp+QjpFye6FrEh3Y1fk8jPT3LAdDoVZROS8W1Pwa1Uos9dzRWg5aNmhDt/7x/2BoDDEt2Pgtb/g2TfwBn3geD2e1kWabC4WZKbBQKIbBaw9tRubnhTHvr29fzyO5HWFKwhHnGbBQBA1pFOok3jqLP4aezyU4XIc4enYZz5UoOmKMIKZRc+Mc7iUtNH0qJIxwlTmqFEXL4cW3p5PkRelSBAGft34OIlalvzUSBTHpJGTU1NZSWlqJUKj/XXwiBaUEW89zhJ6dlvQOMW5BDznwjBX0T2Vk/Bn2Cj5UdNnTjR+HasIEJEyaQkZExrGNMCSGYHhfFhgEn0iE3ev3oRHTJAyj65xMXzKc3qKah8X7+m8J9xoWFlExKR9+Xj4YgnXkTsRp1bHn/bfofe3yoxDm5CPph7T8gfQKceudBqyiAdl+A/kCQMSYDADt27ACgoKAAgPca38OkMfH7Sb/H1r0LvTuP5BtHo4zR8tZjldilEOaJCSwckUz/s8/SGRdN6ez5ERPa7xBHRWEIIU4VQtQIIeqEELccof5qIUSvEKJi8HX9IXVXCSEODL6u+mzfY4n942a6fQHWR8PI5hCF0SsB6PRmo9RocCqUBAIBysvLv/AaQghGpMVQ4JL4oDecI2DRkvHYdH0E2uciyyqc6YJmtRN/UxMhp5OysjK6u7sZGBg4HmIeE05PiKHTF2D5oMwQPvw2zp8EKDmtsZd3BwRudwONTQ8BoFAqmH9VKSUlJZicRZjUQbpSRtKSGEfbo/8m0N09RNKcROx6DmytMPc3hykLgIdbegAYbzLQ2NjI5s2bKS8vx2w2s7N7JyuaVrAwayHOFY14dS3EJI9FGaOlvdaKZPXTlqHhr5eOwfLQg/TVHSAkBBkjyoZCygjHiG+tMIQQSuAh4DSgFLhECFF6hKavyLI8ZvD1xGBfM/AHYDIwCfiDEOK42NzJIZnWmn6+P8WALIWY2NmBYfxWPO0GDC1djF54Olu2biM2Nvaw5PZHQlccx5j+ILttLiRZRq1WIWW4iHel0BUaQ0Kpla64TgC8VfvIysoCoL29/ZjLeaw4KymWIoOOX9W00uzxHSxXJYWdusZ6k6j2qOlXFdDYeD8eTwsACoVg2nkF6DyJCFmJxZiIrBDUx5tou+lmQjbbEceLcBQI+mDdPZAxCfIPD03e6w/wVHsfl6fGU6rXsHTpUmJjYznttNMAeLzyceJ0cfzAcynd1R+AIoS5YAoAe3Z2IyEzZWYG9tdfp+/hf+OfNR2A5LyC4ytjhGPK0VhhTALqZFlukGXZD7wMLP6KfU8BVsiybJFl2QqsAE49CnP6n3S0DHBjmZp2ZYj5O3dTFv0xqGD3ujJUag0JI8fT0dHBzJkzUSi+/GPSj0ykVFLgkGUa3OGb59lT5qOWtDy6Kx3Ja8I43oZbo8C1fj3JyckoFAo6OjqOh6jHBKUQPD0yF2swxFvdn4b6UJp1AKgNo5ku63il1wtAT8/7B9vEJhk49XujUfviyFT6iBsxgc7URDw1NXTeeuvxFeRkYu8bYG8/4upi84ALgItT4lixYgVWq5WFCxdiNBoJSkF2du9kUfIC7Ls30jX6UYyGAuLNM8IJkvZZ6FLKzB+Viv3dd9EWF2MrzEOj1xOXFjm7+C5xNBRGOnBoZL22wbLPcp4QYo8Q4nUhRObX7IsQ4gYhxHYhxPbe3t5vNeFef4CLmtvo1ClI63yIWfUSxqxduLqN6GxOJi+5kG27dhEbG8vo0aP/5/WEUjCxNAWAbXu6woLlhc0UM9Dw8YHp6ON9eM+Ix/rSSwivj6SkJBoaGoattRRAnkFLiVF38GYDoNAoUZo0BBQlnDLQT63TgtJQTFPzI7hcdZ/2HZPIiLHFCKWPhoEkfD4vrlMX4Fy3HnmY+qmc8FS9DTFZkDf3c1XrrA4MCgVdm9ezZcsWpkyZQnFxMQAb2jfgDrqZ3z2ersKn0GgTGTvuBVSqKLYta0Tq89EToyBVr8CzZw+e0eXUbFrHyHmnoFB8/uwvwvDleB16vwvkyLI8ivAq4mu7+cqy/JgsyxNkWZ6QmJj4rSZz24F2WqQgf62wcH6iHn1iJ+r4PvqrTcRNmk/J/FNpaWlh3GDgwK/CyHGpCBn2VfUQsvuISzEi6QKkO1J4q2MO3gEN3on9hJwOPLt2MnnyZDo7O4e1tRTA1NgottpdBKRPD791pfF4+jOYYckiWqXnI3f4+aCu/h+H9Z02JxzEzqBQ4jeY2dTZhFXIePZWHT8BThbqVkL9Sig9+3Oriz5/kNe6rExVSWzfvJnJkydzyimnIITAF/Lx2/W/Zb5iOobOKvxR7eQX/gKtJoHty5vY9l4TNXqJ2DFmXBs2YFPAqsZqTAmJEb+L7yBHQ2G0A5mHvM8YLDuILMv9siz/d6P7CWD8V+17tKl3e3mnZ4Bz2zxE+xq4bs8+TCPfx2dX0+hfwNU/+wmbN4dDcJeWHuko5sjo1ErSNSra9AJPVT8KhSB2hIIMSzGLJwbo2xMPsV58o8G9dRtjx44lIyODqqrhfXOcGhuFOyRR6fg0MVLsmXkItQJZmszFmlTebd1IfMpF9PV9TGvbswfbJSUlUVw4Al9UO93xM1Aao6jITsaxIRJn6qjSvQ9evhQSR8DMX3yu+rHWHrySRGHVDpKSkg4qC4DNHZvRO9X8tOE8+vPfQq/NITn5DPZt6GDL0gZEjpF3NT4umZJN32OPU5WXjtpg4MLb7sRgijnekkY4xhwNhbENKBRC5AohNMDFwNJDGwghUg95ezZQPfj7h8AiIUTc4GH3osGyY8a/mntQSzJX1PupK2ijbX8/hsQeWvbmMu6i69mwYQObN29m3LhxJCQkfK1r5xh1tMeocG7oIOT0s+iMcMz/mO0h1nRPwmdTYz9bxvbeMoK9vZSWltLZ2cn+/fuPkbTHnikxRgA2Dhzik6FSoMkx4VdPY07dRgA61KNJTFhIbe2f6O//JNxOCC68+HxM2gTMOgs95nm4tWp2rVlx/AX5LlO3AoJeuOy1gx7d/8UvSfynvY9ZWgEdrcyaNevgmZ036OWJyieY551AZ9n9+PQdFBXfihBK9qxqIyErmv8E7EwvTKBcOKlpbcCqVjDlvEswJSYNhaQRjjHfWmHIshwEbiZ8o68GXpVluUoIcbsQ4uzBZj8WQlQJIXYDPwauHuxrAf5MWOlsA24fLDsmuEIh3uy2cHqbn72xuzi/sZ0DJVFIIVhhOQuDrYmVK1cycuRIzjzzzK99/VyDlrZoJcEBH31P7SUpNYai02Iw29IQ2fF070ogmBqkb0o3Lddey5j8fJKTk1mxYvjeIJO0agoNWtYd4sQHoM2NIeCJo0hbjF6GrV3bKS+/H7U6no7BOFMASqWSKbPHIam8xA0kkmhOo0olsflvdxxvUb679NaGo9GaUj9XtcfhwRGSSK7fT3x8/GGr6heqX6Cit4KF5hjc5mpKR9xFQsJc+toc9Lc72SX89Lr8/GRBIR2vvsK+tASyS8oYOW/R8ZQuwnHkqJxhyLK8XJblIlmW82VZvmOw7DZZlpcO/v4bWZbLZFkeLcvyXFmW9x/S9ylZlgsGX/85GvP5Ilb3O/DLcEpXiAULT6F/6RYMRRYc3enokuLYuOZjiouLWbJkyf+0jDoSuXotFkmi6bQMAh0ughYPi06ZjMc0wOiW8VRZ52JrjMI5M4ivpYW+226jtLSU/v5+fD7f/x7gBGVRQgwbBhzYAp/muNCNiAcgmPYjZrtcvH7gdXb07CExcSH9/WvwejsPts3JyQEgpLWzJ+sSUlRaNuzYyK4nHj2ucnxn6d0PCUVHrNo0uDLUt9QfZhHYbG/m6aqnOSN2ESFNBZpQEikp52Lv87DswT0E1YJ3rQP8eUk5BZUb2PDRMlAIFt70c5Rf8dwvwvDjpPL03jhgRx0KUuryIT94J03z4tFEB9nePplCby35+flccMEFR/Tq/ipckBJHpk7DbXLYaig04EOpVpB1CbjUNpLVk0mxelFog7gunIF74yaS48M31u5h7LR2RmIMQRnubuo6GOJDnWJAFa/D2ZzJH3r9JKiMPFTxEJkZVwGCmprbDvZPSUkhLi4OT1QHtk4/wWv+RII/xOoV79LfPnxT254QBP3QVwuJxZ+rkmWZ5b020uUgxlCQsrJPnez+sPEPmP0xXNWRi8u8m6TkM/C6Arzzz114PAGe13n48RklXDYmmb1/u5Ou2CimnX8pMUnJx1O6CMeZk0ph1FkHSPPIBBOC1LRVETW3FVtnEiq3kcTUNC666KKvbBV1JBI1aq5LT2BfwE+7XhAaCK8azhu9GHtJMwa3AYU3/A+1nyq8skScNezDMFwj2AKMjTZwXXoCj7f18e/WsMmzEILYcwsJ2kIE5au4RpHIju4d1LqcJCedjs1ecVC5KBQKpk+fTlDloEDh5P1aO7PKxyMkma2vvTiUog1vpBC8dQP47FCw4HPV22wudjncjO9rJy0tDbU6nMd7ZfNKKrp28ff2n2NJfQe9NpeCsl9Qu6Ube5+XplIjIZOa62fm4dq4kT61QKFQMH7xecdbwgjHmZNKYXQO+En1ytj6VtE5Q4NQwL6mWYR0sVx31RVoNJpvPcapiWHLkHVJKoLWsNOaUqGkfHwWEhJV9mtQu2UMaVYak+LwP/8C5WVlrF+/ftjm/RZC8OfCdBbFm7ivqQt7MOxbosuPxTA6CVdgPkvq9hGnieGZqmeIii4lELDg83UdvMaYMWMw6I0E9a146+yoFl9Aut1N7ab1BCPRbL8Zy34GVW/Bwj9D8Wmfq95hD1u2xR+oOrgtaPFa+M3633CptBiN14nX1EBaxjkolXrqd/VgTjOyvNPCghFJKBUC1/r1WKONJOcVotZoj6d0EYaAk0ph9AiBwW9nS8Nu4kqc2O0J2EMJ/OjGa9DpdEdljBy9lnStmt2J6oMrDICJBWPZlPM2Xns2ga5iTBlu2nKMHKjYzqSt28jNyeGDDz7A4/EclXkcbxRC8KvcFBwh6bA0rtFzMpAlNUHvqZweEKxvX49GH478a3fsOdhOpVIxfcY0AtoBxgc9PNGqpGDcBILING7fctzlGfb01oZzXUy9Gab/+IhNKnr60Qd8ZJnjmD49HMrj8T2P4w16uThwJv6sRgDi4+dQuaaNzjobmvxoHN4giwYdVS0N9Vh1GrJHjTkuYkUYWk4aheEOhrCplZjtXlKm96GJ8lLbPImbbryWFPPRtRefHBtFRYwSb7MdyRM+CC6ILcBSWEdT4Q4aai4HSUn+aTZ256bStPpjxjc34/f7+eijj4ZtqO+R0QbmmqN5rK0XTyicB0OdbEQ/JhFH8ALOaErAL/nZZetDq0mmtuZPBIOOg/0nTJiASqlCre2lZ3UnnWmj0PsCrHjsX7jtkRhTX4ua98I/p/zgiNVer5dtHV0k+L1cccUV6PV6Pmn9hOern+fCwgtQdgQJpvYDCjTqHLYuayS9OI5dhiB6tZIZhQlIoRA7bb0ohGD0ojOOn2wRhoyTRmG09oStQaKdVuILrHR2FZIx7odkJ8cf9bEmxhjpVUGr10/fM1XIIRmlQsm15dfyQfyz9Bkt2FqnoDE5MWdmU1mcDS+/wjiDgV27dlFXV/e/BzlBuTkriV5/kJe7PrWONp9XiCY3hjj3T1hkL+W56lcoL/8XPn837e2fnlFotVoKCguQYqyMCCr5U72acc3deNwudr3/7lCIM3zZ/x6kjoGYjCNWb9u2HYvWwIS0ZKKiopBlmccqHyM9Kp1fZP0Y2RciEN2FXpfBmucb8DoDTDwjhxXVPcwuSkSnVrJ31Ud0axRMyCkiKs58xHEifLc4aRTGro4BABLYjEIpsbN9LKeN+3xSpKPB5EFnttp5qfib7Piawk/H5xedz6TUSawrfx+Vz49Qu8mZcBreYID2yWMpfPsdoqOjWb16NYFhum8/LTaKyTFG/lzfQY0rfIYj1EoSripDHe3lh50XU9W7l5eathJvnkVD4z+xWj/dcho5ciT+oAdPVD3jk9J4K38BKQNOtrz5Cg27tg+VWMMLRxe0bYeSL37qX97chlejZVZqOMzOju4d7Ondw9VlV+Pb1QcKgVfVjt+ZSt32Hqaem8++oJ9uu49TypPxOB1sefMVTG4f5ROnHi/JIgwxJ43CWNu4H0NQJjG2hlBISVb+fMzGb3/IfSSKjTpMKgV74lSgEnir+gFQCAWjE0fT4e4gMTMcBvxAdR+Fk6ez12OjXfazYNw4Ojo6eO2114ZlYEIhBI+W5eANSSzt+TSKrUKnwjRZiVZK4GYu4Km9T5Gefxs6XRZ7Km88uDVVWlrK5MmT8Rg7GKfo58ORCxFpY4nyeHn373+mo7b6i4aO8F/W3AnIUHJk59N+t4d3YtOIkSXOSYrDFXBx59Y7MevMnJ12Jq6tXcgT+nF76+lrNFMwIYmCWWn8/NUKSlKiOaUshXUv/AfngIXSjj60/yP8f4TvDieFwnDaO9mmjSVzwEZsshVPXww/PufzETuPFkohmBQTxVqbE90IM84tnXjrwjfP3JhcQnKIuPxwOC21op+Y1MWk5eRTlZ5Aamcnp59+OrW1tXz44TGNknLMSNGqKY3Ss83mOqxcN2EEKtHMorYJ+IN+Xq//gOKi2wgGHdhsu4CwwjnllFOIi0qg01nDkqho/pZ9KnOLR6PxeHjj9t9h6Ri+eUSOOX11sOPpcPrV5CPHQnu5vhWL0cRv43XolAreb3yfWmstf57+ZwIb+5ADEt2pLxPymejfv5AJp+Xw5LpGHN4gd18wGp1KULdtM+khQXJcAvqxY4+vjBGGjJNCYdy17F1ao7VkufdgjBrAYC1BpTy2oi+MN9Hs9dN3SiaqBD39z1YTsvvJjQnnR+7QhWPtRMVvZ+/aLiZdeD1BpZJN77zKxIkTKS0tZd++fcd0jseSiTFGdtjdBA+JYitiMzBFf4jCaeSv9p/zYvWLBDQZgIIB246D7RQKBaecuQBJ5UXXXUmKXebJCZcxJzmHoM/H9scfHgKJhgk14RzqTP3hFzbZb7UhZJmzc8NxP3f17MKsMzM5NBrHmlY04/TY3Nux1k9izkWT2NBn54FVBzhzVCrl6TF01tbgcdiJb+kg8ac/RUQ8u08avvsKw9ZOq68IdTDIIsVyhBvGz/7lMR92UYIJpYA7OnqJv3wEciCEY307uTG5KIWSnZY6ogMxJOZsRRJ+tq30UZRTQB1BGv/9MMnJyTidzmF7ljEjLgpXSGLrZ1YZhkIl0Yb3GN2Rx/kd87h59S8xGIuxWDYc1q6kpITysnIChj7O9Kj5YEcn+j/ciUmhonPLZgLDOPnUMcPeAZv/DamjITbrC5s1e3xE+73EmaKRZZldPbsYnTgaX6MdAP/EGhASRu0sEsrN/Pr13UzMNnP3BeHcMPWPh0O2FFx6OTFnRqyjTia+2wrDbaH7iRvojNIQ63aQbG6EA0biSkcd86FTtRpuyU1lRb+dGh0YxiThXNeGssnPwuyFvHngTcxJFxLQy+RNu4v+hgEy5l0DwIFXXyJGG3aCGq55v+fERaMRgg/7PmMOmz0dU+jfGMvVnNe7gPy6JFpIw27fxcDA4Yfaefl5hAggq71M8qpYWm0hZdx4HDo1jpWrjqM0w4S1/wB3Pyz+8hVYZ1AiUQ6fjz2590laHa3MzphNoNOFMlZLa9ezeC1ZJKVN5IUtLXgDEn89dyQ6tRJfQyNdu3ehVarIvPlHx0OqCCcQ322FseL37O4+h1ajkjTRhlIfxK6ddzDW/7Hm7KRYALbb3cSeU4AyVov94xZ+MPoHyMjc1VNHvnIqurRWUsY9z951TnSGKKxqJfLycEpTq9X6JSOcuBhVSibHGlk/4Di8YuQFCG0UsYZn0ebFcLn1TJb32tFqU9i798eEQp86LmZmhrdMEkthtF9F164+kstG4lOr6F76DvIwXX0dEzp2QcWLMPoiSCn/wmbd3d30KzWka5S4Ai6eqnyKOZlzOLfwXAJdLkS6hNtTh711Eqn5sayp6WFcViwFg7naLU8/jcOgI7Gg6BsF6IwwvPnu/sWdvVh2bCRLmY9Vr6Uwai+KXRqyF91y3KaQpdOQpFGx3eZCoVESNTUNf7OdLDmNq0qvYmvXVqIn/hNFXwaxBevQJL6FQpNJf1I8oXfDKUWGq8KA8DlGtdOLM3iItZc+FnJnIbp2YRiXRKw/Clu7jYSsH+Pzd2O37z7YNCEhgYSEBAbkVuyxStLqPAhVOINve2sTnbfeOmydHI8q/fXw/PlgTIK5v/vSpnet24Jbq2NKRhp/2vgnHAEHN466kZDNT7DHTSAxbNFnii3EnBPN3nY7E3PCPhbB/n563l2K3aAlpajkmIsV4cTjO6sw5JbNNHp/zAd5zQAk9/bR47iBsQUpx20OQgjGmQzsHsxGp04J+2eErD5mZ85GRmZ50/vUJz9OsDuKhJFvoUtR4A368U6bhM7jYd/GjcdtvkebiSYjErDT7j68IjYbrM3ois2gEvyw62Lebt0LgM32aTwtIQTTp0+nu7sLUdhHt1Ji1wovhpg4LONGYXtnKa51646jRCcgAQ88fx7IElzxJkR/8fd7S5+VV+IyKJb8eAZe5f2m9/n5+J9TnlCOa1MHCOjXheN7lU6eyN4OO/6QxLjsOABcGzfREq1DkmXK5y48LuJFOLE4KgpDCHGqEKJGCFEnhPjcI7wQ4udCiH1CiD1CiJVCiOxD6kJCiIrB19LP9v2m2Kua6Y/L4b78EjJDLfCujlN+fdPRuvxXZoRRT73bhzckoYwNn0uE7D5GmEcwOXUy926/l8TkNm6rvR2FS0Xq6LUIhQ5bUREjrFaabbZhm5FvYowRg1LBq12fyYkVlw0BF0qFg9iz8in15FGxu5KQKhnrwNbDmo4ZM4bCwkLob2CdIYDPFSS1aCqt/d205qRjefa54yjRCcjul8HaCOc9AQmFX9r0rv3NqENBlih28/L+Z7l8xOVcXXY1AN5aK5qcGNrbq5ElJZmFJby8tQWDRsmUvHA0BF9tDb0xRlLyi4hPz/ySkSJ8V/nWCkMIoQQeAk4DSoFLhBCfNQDfBUyQZXkU8Drw90PqPLIsjxl8nc1RYme1hrvLA+jxcMH6ZRT/5P+INRwbR70vozRKjwTUur0oY8LjBwd8CCG4b8595MTk8MCeO7j/iim80rIYdWwPhiQN7TUNTFu4iDiLhXfefHNYWktFqZRclmrm7R4rG6yHnGXEDj4vDDRhGJ0ICsE58imsslixWNbjdjcdbCqEoLCwEK/bxdmzkhlQSHjFJPInTKEyRkdd1R5CdvvxFexEoe8ArLwd0sZB/rwvbVrv8rLZLzPO2sHTLQ+yKHsRv5r4K4QQSL4QgS4Xre4ulKZP0Khy6XPLLN3dwYUTMonRh8Oeu/fvx6bXkV4y4nhIF+EE5GisMCYBdbIsN8iy7AdeBhYf2kCW5dWyLP93X2IzcOQAN0cJd2cne3XF7IlKYoH/Iz60TGRGYeKxHPILKY0KR8GtdHhQaFUInZKQLRzFNloTzS8m/IIeTw8NvpUsmXkdsgxxOQO4rB2Ypk9jzK4KPH4/e/bs+bJhTlh+kZNCrl7LNXsbqXYOHmj/1+TT2oRCp0KbH8MM21i6lCX4JZnte35AKPTpNlZGRvjrMiVJplUr01NnZ871PyExJZ3qlDjsK1ceb7GGHr8bnj8XFEo4/0n4H4Yc/6prRcgSefJeFAoFt0y6BYUI//v7W+yElG76sv+C2uBl7Pj7eHZTEyFZ5trpYb8hWZLoqj+AJCC1MKIwTlaOhsJIBw5Ni9Y2WPZFXAe8f8h7nRBiuxBisxBiyRd1EkLcMNhue29v75dO6JU3PuGecdHkyPWM7aimzZRBiunohC//uuTqtWTrNLzcGd6WUcZoCdn8B+unp01naupU/rHtH5ji+/FKRZgyepCkAK3tzaQqlZhCEtXVwzMkRqxaxUuj8zEolFy6p4F2rx/i80EbA9XLAIiamoZsC/C39Ht43R6H311LTc0fDl4jOTmZ+Ph41q35mDlz4lHK8M57zYxbfB5ejYoD99yN78CBoRJxaNj9Igy0wHlPgjnvS5taA0Hesjgp7GljnWspV5ddTaLh0wco17YuekpeQRndRVby3Si1RbywpYVTSlPIijeE26xbR7NSQqVUkTVy9DEVLcKJy3E99BZCXA5MAP5xSHG2LMsTgEuBfwohjhgRUJblx2RZniDL8oTExC9fLTyXlIVB8vEr/kprYAq5CUYUiuNjSvtZFELwvcxEttld7LC5UCcZ8NUPEOgKO7QJIbhnzj3kxebxszU/w5Q4CnXcACqtiY8e+ju6ieNJbWygsaFh2Ob9ztBpeGl0Hs5giF/VtIJaD+OvhH3vgLM3fPitFOh6BKNzrmSrU0Vnz4fIcjhEulKp5LLLLkMIgbVjCwNambYt3UQXjkIIQb05itaf/gxZkoZY0uPIzmfDDnq5s760WUiW+dn+FnwyFPfuI9mczI/Gfuo/IflCuPf24EjagaN1ErlFC3hjRxs2T4DrZ4ZXF6GBAZruuIOOuGjK5ixAHxV9TEWLcOJyNBRGO3DoCVjGYNlhCCEWAL8DzpZl+eCdT5bl9sGfDcAa4FsFpnn7gw3sSzSwKLQMpUPJloEychOM3+aS35pLUsyYVAruaeoi+vRchFZJ31N7CR6yNfXw/IcxaU081/gJQiFjTC/C4wkwMHMqaT4fIUmipaJiSOX4NoyI0nNFWgLrrM6wme3IC0AOQd0KhFKgMusI9nq4buR1eNTpILmo7lpzsL/ZbGbhwoV0d3dTPEVLbEDwx2drmHz+ZXTo1bT3dOJcdZI489k7oXM3lC750q0oWZa59UA7H/TZmV5fSZfYxA2jbji4FQXgb3PgMlciq5zolNPwyjKPr2tkdGYs4weto2zL3qMm6EYSgnFnnnOspYtwAnM0FMY2oFAIkSuE0AAXA4dZOwkhxgKPElYWPYeUxwkhtIO/JwDTgW8cQKliwMnPFBoKnT4Wat9mYKCUaqs4aEc+VBhVSn6Rk8Iqi4O/WSwkXFOO5AtheXH/QT+CZGMy/57/bxrCEcGJy69HrwzQVLmJsj/+EYCahx8maLF8wSgnPgviTQRkmVUWB6SMgujUsJWPJKFK0BPs92BUG7lh4l0AbGl86bD+I0eOxGg04g01oYxRU9oWRFEyi6i4eOqzU2n73a2Ehqln/Ndif3grj6JTvrTZOz0D/Ke9jzPwUt5eT0JeAmfln3VYG1vzXjpHPobfkcyMsy7lHx/sp33Aw69PKT7o4Fq54n2aEmMZOf8UzGlfttsc4bvOt1YYsiwHgZuBD4Fq4FVZlquEELcLIf5r9fQPIAp47TPmsyOA7UKI3cBq4C5Zlr+Rwuj1B7i8oo4oP/y4+yV0eBlgCiCYV5L0bUQ8KtyQkchVafE81NLD8yE3Mafm4G+242/61MKnIK6Au+b+i3UDUcTmbSRhtJ+OujriS0vRqdVYgJ577x06Ib4lk2KMpGvVPN3eF34ynv5TaPwEVvweVYKeQJ8XWZLJiJ+AT1bicVUd1l+lUjFx4kTq6urImaXBIAtqqgeYddnVWJVQrxF4h+lZz1dGkmDrY+HtqKQjR6MFkGSZh1t6KDRomdFag11jp/Qz7f1+CzXBX4GkxN/6e6LjYtnebGVafjzTCxIA2P/i8+zwWEk1xTH/2iNn74tw8nBUzjBkWV4uy3KRLMv5sizfMVh2myzLSwd/XyDLcvJnzWdlWd4oy/JIWZZHD/588pvO4cm2Xvolmd/VbSc25z3sjiz+XZvB9IJ4coZ4SwrCZxV3FGawMN7ErQfaWZejRxGtwfJKDZI3eLDdxJSJlJX9lp7+DGJG9uByB7B1d5GclsZAbi4DS9/F39Y2hJJ8c1QKwfcyEtk44Azn/Z58I4y/BjY9iDraC0EJf5sDIRR4ValES30EQoebE0+dOpWUlBR2VHyMT+Wku8nOiJlzSc7OpTvGiL+paWiEO17Ur4S+Wphy05duR93d1MUep4ebM5PoaGujX9tPkbnosDYdba8TUPUgtvyInBHlhCSZAz1OSlLCZxSeqirWvvocRgTn/PU+lJGotCc93wlPb09I4tmWbib19JMw4kE8nmj+ve/7ZMZH8/Cl44d6egdRKQSPlGUzKtrAD2tbaDkvh9CAD9f27sPaLcheRI0jCpXOiyHGx1v/uJ1Ro0ZhASrGjqX9F78YGgGOAtdnJLIg3sRvattY0W+HCeGAi/qoaoRWiWNVK7IkExczjhRViNWNbxzWX6vVctlll6FQKHCaOgi2ewgEJfImTmXAoMX2XbeW2v4fiEqBsi8+S7AFgjzS2svZSbFMDboI+AP06nopjD3csa+3fQUaRwb9tnxKpqXS1O/CH5QoTjER6Ohg489+jEOrZurl16FPTDjWkkUYBnwnFMZb3VYssuDUmP8QCinYt28htTYjfzyrjBiDeqindxhGpZLnRuWSoFHzG7sVTbYJ19bOw9rE6eLo0eoBKMj1YWlrJUmnZvLkydTm5tDe2jZsw3urFIJHS7Mpj9Zz475mduvzQKVH0b0N0/wsvPst2Fc0M6HghwRQ0NnwV5x+52HXiI6OJj8/H6EfIMYrce9DOyieNhOEoKZ+eHrFf2W6KiF3JqiO7IQqyzK31rXjDkn8KCuJAwcOICPjinFRGPepwujvX4vdvwtdzxiKzspDq1fx3KZwGJ0yk2DXD25gd6yOtJx8yk4/cua+CCcf3wmFsaLfTrLPQqF2M1V7ZtDmMDMh28z0gvihntoRSdSouS49gWqXF0t5HMEeD0GL9/A2WSMI+gyEMtWgVPD2A/cwcewYhBB0pKdh/+ijIZr9t8eoUvL8yDzMaiVXVDXTmrsIKl8lqsyPcWIKjtWtiH1RRCVfSobKxV8+uZ6QdHi62sLCQkIhL/4YH9baAQ74DKRojdQ7B5CGqfnx/yTgBVsrmL84F/0/mrp4rcvKr3JSSPG62Lx5M1ajlcmZk1EpwltKLlcDlZU3oXVkMHDgNMpmp9Pj8PL0xiYunZSJ8c7bqAm40UeZOOf3d6BUnVgPXRGGjmGvMGRZZpvFTqFyP4G+POyeJLr0WTx6xfjjFsb8m7AgwQTAW+bwHD37+g+rv7D0Ymp7slGltJCbp8Njt/PB/X8jPT2d1sJCOh74F/624ZuqNEmr5oVR+fgkmUtzf8GAQo948UJiF5nRFsUx8HYd45TXIQktcd6drGlbc1j/rKywt3h6gSA9pODxjw5QOHUGHpWC5ldfHgKJjgPWJkAOOz4egZc6+7m3qZuLU8z8PCeZffv2EQgE2GTexMLsT4MFNjc/ihwMkbrr53iTElEoFaypCTvDXqbrw7VxI+6kRDJHjUEXFXUcBIswXBj2CqNxwE2fJJOvrKKpPReFy85N588nPko71FP7UvL1WpYkxXJ/Tz9N+VG4tnQiH5LOtCy+DH96FkIh49KMY038Qrob69H0tuPUatlTXIxz1fAOiVFs1PGf8lya/HDt9Gfx2ToR795E/GUlqJON2F5qIz3mXMYaQrxbc3iQQbPZjF6vRxHtRqFSkFbppDZ3BgB16z8ZCnGOPZb68M8jrDDWWhz8qqaV2XHR/KM4EyEEbW1tBPQBYmNimZcVjjXl9/fR1fkOpvbp1NlMJBbE4vIF+c+GJrKNCvRPPIRsjsPpcZGQmf25cSKc3Ax7hbF0W/gpu9DbRbctlYBSz+whihv1dRBCcGdRBnqF4IVSA8FeD7YPmw5rc8mEHwOgMFqYqxrBRvNMeiu2kWjQ0ViQT9/a4R/ae1pcFP8syWSjV8nPpz+OXPs+Cns9CdeUodArMayehEJAtGfnYbkvhBBkZmbS0FzHrMuzSQoJOtY6SVTpOGDpJhQMfsmow5CAB9bfB2rD56LShmSZX9e2kqvX8kR5DmqFQJZlmlubaVO2cUnJJQe3o1pqn0UWAeg5jU6divK5GfzopV3Udjv4W0wHvn370P4onA88PiuiMCIczrBWGE6rl/Vt/ahlP9reACIQ4IKrrhmyMCBflzi1imszEnnL7+G9mQk4P2nDufnTA/DUmGL8ksCVvpKogMwIw0RqYstw7d2BpFSyQqvB09w8hBIcHc5LMfOb3FTeII2/5d4IWx5BadKScE05KosZlbeU0To33a7DrckWLVpEKBSitn0XbZlajJYAOfkT8SgEHz9y/3crudIHv4G27XDuY6AzHVa1st9Ok8fPL3NTiFYpAejp68Hv9eOP8nNe4XlAePu2u2MZemsJ+/uTSC+K467Vtaza38Pti8tIr92FOi0NV1L4gSsxM+e4ihjhxGdYK4xty5toi/eRSz1WazJxrk5GlX55ToATjd/kpjLPHM3tBh/bx8Qy8E7dwQNwIQR+jMhRNkZO0JDmhi1RY1H4PJQlxtGbmMhrjz6KFAr9j1FOfH6cncRlqWb+mXUpy1tbwGNFnWJEmxtDXPdk4lQyB3oO32pKSEhg3LhxVFVVYcoNPyRoC+eS121l77rVVK4avoYBn6NhDYw4E0ac9bmqx9t6SdOqOT0h9mDZxn3hxFsXTr6QGG0MAAOVe/GqmomLms3AgJ86v4/nN7dw4+w8zjf7ca3fgHH2LPpbm1FptcQkJR8PySIMI4a1wlhms9FkimWUVIFcD3PPPXeop/S1USkEj5XlUBKl4w/pEAC81Z8egEuqBMwaSIzrR5ZkYlWxSNGJqDwOpppMNGg0LP/HP754gGGCEIK7ijIp0MADaecj73gWAF1xHKamkQBUtbz8uVXDtGnTMBgM0LqJAaWXlgE1Y5IzifMH2frmK0jS8FemBP3hyLQJxZ+rqnZ6WGd1ck16AupDVtb7GvYRFEEWloYPu2VZoqHtbgB06YsAeKOuh9NHpvB/p5TQ+ac/oYiKIuGGG+hrbSYhIwsRydkd4TMM22+E2+1nWZZETqiBM/srmRH7ESOnDs+0kVEqJb/NS6M7GOKTAgOemk/zeGuMxZhVMrIi/MQ4UW+gVxVHX2szC3/6U/KCQXY5nbjbh6dfxqGoFYLrcjKoMI1gx853obcGw5gk1MF4hC8V3Ht5uurpw/qYTCYuvfRS5KAPd1wV3fv7Ud/0O7ItTmx9PXTu3Ts0whxNBprDgRrjCw4rlmWZf7X0oFcILkv71IS8vb0dX4sPv9lPlDZs5VRX+3cGdOtJc1yLvSfctlclcesZpfhr9uPZvoP4668Dcxw9zY3ERw68IxyBYasw/rBxDzajnrMUb6HuS8RUcj6ohybnxdFgrjkas1rJ1kwtvoYBJH/4ydgUOxGAgc4XyMwV5PYE6QiZsHZ1EfL7mXjaaYRUKva99OJQTv+ocWFyHCal4MmUM2DbEyijNRgnphDXPo4Crczr+x7/nE9GWloaF5x/PiqViwFTNdV1gpJf/hqA+n/9cwikOMr0D1pHfcac9rG2Xt7stvL9zCTM6k/DdqxYs4KACFAyowSAttaXaGl/nJi2ueSOvInKPT04hMySqVmkxerDPj0KBdFnncXyf92D1+mgZPrs4yZehOHDsFUYr8hQ7KpjEptIcVWSf+GdQz2lb4VCCMZGG6nUCwjK+BpsACSbJ+GXwJFmYJrvNyDByMwCBDIfvfUOBZMmoZYktrS24ne5hliKb49RpWRxspkV8dPw14XDlceekUfcwDwUspbFUb1U9Vd9rl9xcTHG/AkEtf1UHNhM6mlnoFQo6K0/MLyTK0kSVLwAQnHYCqPB7eOPdR2ckRjDr3JTDpY7nU4aDzTSFN3E3Ly59PWtoab2Noy9oygu/gPa3Bi6GuxY9XDrmeFghK6169CPHUtjbTV12zYx54rryBn1rbIMRPiOMiwVhsVux69SMUX3Cfr+VIpmfA+F+vjn6z7ajDMZqAsGsOoV+OoGAEiNzmKZTY3CGEIZ14la6ac8YxTN+kxqlr+GQghOGTeO3rg43vjb34ZWgKPEfLMJp0LLVikadr2AUCswZZeS2HA++TqJlyruJCh93mz22nMW0h1IxaVt44NlnxCfmY3DoGPg9TeOMMowYdXtUL0UFvwRDJ+G6X+ktQeVENxZmIHiEAfVNRVrEAjGjxpPgsJL5Z4foXVkUBTzF6InZ7L+vUb0fpmMEjNqpYKQ3Y63qoqoGdNp2LEFXbSJsad9/mA9QgQYpgrD6Q3ne04PuCjoOQP11O8P8YyODqclxqAWgt+ON+JqDYc9j1JH0a8M57R2j5hOsnI/rhYLbUmjkf1eOmqrmbBkCaNVKmoUCrqGae7vQ5kZF4VaCFbmXgDv/hhat6EflYCpeTpIOmK9O/jrlr9+7gA8IUrLgsWnoPTGs3XXWox5xfQbddRvXDtEknxL9i0N+16Mvwam/fhg8atdFp7t6OeKtHiStJ+G7ZAkia07t+JT+rh+6pXs3nU9Cq+WfO/txC0qpeOAlT3LmqhRh1h4Znh7y7OnMty5qJCGih3kjBqLQqE8rmJGGD4MS4UhNOE97LGVZxF3yve+NMzzcKI0Ss99JZlsM8LvYwJIwRBCCE4vuAKvBB3xcSQYe7B0eUkpLkcSCrYvextZkph7+eUoQiHee/GlYe+0ZlQpmRJrZGXyHFBqoPI19MVmosfmENc2i/FGmQ/rXuX9xvc/1/e8STmYkiaiCOmocUqYjFHsw4+3oeH4C/JtkGVYfy8kFMHpdx/8jm+wOvjF/lZmxEbxx4K0w7ps3LERhUWBsciIa2A1vmAXKXu/R9JZUxAKwc6PWgioBbtSFBSnDoYw311BSKHgo1XLCXq9jD9jyfGWNMIwYlgqjJBCiVIOkmDRoMkb2mx6R5vzUsz8xGhieaqaD9Y0AjAzcxZdAQUW9wHiy0YSktUsSRNsjJtMw44t1G3bTGxODtMTE2nVadn19ttDK8RRYEG8iVpPgI/yL4b27QBEz8kktmU+QpaZH6Nia9fWI/a99urR6Nzp+JwW8ueegs2go/E/Tx3P6X97tjwKHbtgyg9AGT7QPuDycu3eJnL0Gp4sz0FziNmrLMu8t/k9PEoPF81bSH393eilAoyOMhQGFV5XgOa9/ezRBJlZmoQQgkBXF9ZXXqWqLJ/OulpOu/nnpOQPLz+mCMeXo6IwhBCnCiFqhBB1QohbjlCvFUK8Mli/RQiRc0jdbwbLa4QQX55zchCXMFDm6UM9xoAYJl7dX4efjc8mXoKn+gfw7O0j25RNe1CHwtdI9MgcAHL7qnAUTMOpjmbju28DMPt738PocrF97+cPhYcbl6fFMypKz/eTLqPa7oCgD3WCnoTpkzD2jWKGLkj9QM0R+0ab9biSw2nmWwcMANRvWo80XIwCfA5YfQcULIRxVwPgDUlcvqcBtRC8MCqPGPXhyYwarY0oLAriM+MJWZYRCjnJ7v8lqhgdQgh6muwgQx1B5hYnIYdCtP7wh9RqoE0hMeuyayiaMmMIhI0wnPjWCkMIoQQeAk4DSoFLhBCfzR15HWCVZbkAuA/422DfUsI5wMuAU4GHB6/3pQRRMb9xPwUXz/220z8h0SmVXJ2TxPokFZXrWxAI7LoxKJCwG7YgkOirqOSZs2KpjR9N34F91FXXoNLrKQ+G6EKmY5jmy/gv4bwheWgUgrszLw/ngQCi52WSor0QpcrDJKv9C8N/5EzPwh800trZTnRsGh0GNZa33jqeInxzKl8Hnx3m3AKDq4iNA06avX7uLs4kS//5wJprd6xFLauZNHocnZ1vkZx8NmpLEkpT2Bikq9GODLiMCqYXxONcvRrX/v00psaTP2EKE84afk6vEY4/R2OFMQmok2W5QZZlP/AysPgzbRYDzwz+/jowX4Rjjy8GXpZl2SfLciNQN3i9L0Ulh7hwzvyjMPUTlyszElEDL+qC+JvtXDLqp3QHFGxrfpHMEhPVnrmk7HuWm2+8jIBQ8dx99+H2eBkzdgyqQID33nqLQCDwP8c5kUnWqrk8KZr3E2awtTmcGEkIQdYZF6BxllCafIADNW8fse9pI9OoUycQ1NhxinIcei1r3nhpeIRRqXkf4nIhY8LBolUWO3qFYLY5+ohdmvc141Q7GZ2bhCR5iI+fTcjmQxmjxeP0U7Wxgz6lxHlTsjBoVFiee56unAz8fj8Tzzr3hE4FcBhf4rkfDAZ5/vnnqa8P+614gh5++PEPqeipAEAOhOh7ugpfo+0rD1fX4+SKJ7fQumM3LdddT6Cn51tNf7hzNBRGOtB6yPu2wbIjtpFlOQjYgPiv2BcAIcQNQojtQojtUb4QueUjj8LUT1yStWrOSozl3XQ13RvbGZ88HpNpNDFyP4bRMh4plu491UwtzSRz8TWYbG3c+/s/Y54zh0lbttLe28uyZcuGWoxvzU2FeeT4erjam0+jO5wYSaFWEld+K2pPAh3N9x6xX0qMjp9dvIigrMCZEERjmECzRlD/+qvHc/pfn4AXGtdC4adRC/ySxNKeAWaZo9ErP/8vu7drLyFrCEWKAq8nfLM0agsI2f0oTBref6QS14CPFYYAV0zJxltbi3PrFppT4knKzSeteMRxE+9b4eqDv+fB3jcB8HhaCIU+TTy2b98+6urqkCQJgL9t/Rvr29dj9VqRJRnLq7V4ayxIrq/2INXn9HHN01tpbupg2Z2/ZV9bA7Lff/TlGkYMm0NvWZYfk2V5gizLE7ISYoZ6OseFKzIScKkEq/rsyIEQmYmziVKC3RDenrE59eC1c9kli/GOPgV9626279xOvkZDidPJ3r17CQ2HJ+ovIU6t4oXAOgj5uXxnFb7Bm0FxzgQc/YWE1B0EAvYj9p1anE7hpLlIKjvOxESQoWbpm8iD1zgh6amCoAdyPj1PWN5ro8cf5Kq0I+fVfn7d8yhQcMWsK3C5ahFCg3+VBLKML0ZLZ52NTVEhykYmkmk24Fq3jv2p8dhcDqaed8nwWV3UrwLvAMSFw5bsrfopFbuvBcDj8fDJJ58QHx9Pfn4+siyzunU1Z+SdwdysubgrevBU9hFzWi768v+dn9wbCPG9Z7djsbm4smcpXiFTeM31aDIyjqWEJzxHQ2G0A5mHvM8YLDtiGyGECogB+r9i388xbL7g35KJJiMmoWBjnAJvg438tCWEZPAHPkShkBkIpYI1bEm18JJLadWls33ZmxhmTCemej+hUAiLxTLEUnx7chfdwp/an6c+oKDGFX6iVCvUeKVwNNU+67Yv7HvVGTORk4rw6nuRDdm0upz0P/PMF7Yfcnqqwz+Tyw8WfdBnI1GjYs4RtqO2d22nrbUNFFCaV4rNtgujPh/39j6Mk1NptYWfiCvwc/X0HAAGdu2iNSGGstkLKJg45ZiLdLR4qKWHVzPPg9Sx+P392O17iIubSjAY5NVXX8VqtXLWWWehUChod7Zj8VoYmxT2WPc12FAYVUTNPOIGxmFIkszTG5vY1TLAb5NasQ30Mt4nyLvw4mMt4gnP0VAY24BCIUSuEEJD+BB76WfaLAWuGvz9fGCVHD6tXApcPGhFlQsUAke2lTwJUSkEM8xR7IhX4auxEmXIpDYQTZy/AnNWM7Zg2sE4Q+Oy4qhNGEvQMUBvZiox/eGItz3fhT1XnYnivPB+flvfpzuYOQmzQRa8V/lPJPmLVw1zZ85ARuBLTsWlVVL3wnPIJ+r5Tk81qPQQlwNAUJJZY3Ewz2w6zKMboNXeyk9W/4SUYAppaWl4PHUM2LYR558NIRlRFs/ula1YdJCZFs3UvHhCoSCbW+sICcH4M5ccf/m+IbbKpdyjG8f6rDNAoaCn90NAJiF+Nh9++CGNjY0sXryYnJwcAHb37gZgZEJ469rf6kCTEf0/HzY7Dgzwyl+28uYnTUzPisKxfSVml5dJf78nEr2Xo6AwBs8kbgY+BKqBV2VZrhJC3C6EOHuw2ZNAvBCiDvg5cMtg3yrgVWAf8AFwkyzLw3sP5Sgz0mSgXa+gv9aCLMvUKsfhkZTElb5DXzAHqSccJ0mlVJA7bgIOTQy7qyrIOPtshCRxYNWqIZbg6JBREjZyaG3ff7BsRPYkdLZcdN56Htn9yBf2nV6aQbUim4A+iGSMp14p4fj442M+56+NJEHrVkgshkFv6xX9NgaCIU47wjbsY5WPEQwFifHFkJ2ZTWvbMygUOmK75qKIVlO734rHGeAttZcfzMlHCMHq+/5Ol07F5FETSczKOc4CfkNat/FAxWbcSgPXT5hHIDDAgQN/xWQaiyxnsWPHDiZMmMDo0aMPdnmn7h2S9EkUxhUS6HIR7HGjyTyywcB/Geh2s/yRPTjcAVodbuY0vI3b52V0dgG6kpJjLeWw4KioTFmWl8uyXCTLcr4sy3cMlt0my/LSwd+9sixfIMtygSzLk2RZbjik7x2D/YplWf686+5JzgijHoADAT++AwOMTpnOajsoo/YSTLSwY401fKMB5paksCFmEj2N9bQVZpPjcFLR10d11fD3y4hLyscY8tJm7TpYpozRYOwbRYrOx9Ka57/QxFatVPCTi09FkgWhmFy6Y4y0nYjbUjuegratMDq89eEOSdzT1E26Vs2C+MOz7NVYaljesJwzk88kFAqRnGykq+sdUlIWI7WAJtNEQ2U/3SqJ6eNSWTwmnYoP32P3to3k2NxM+9mvhkLCr48U4qXVz/BQxoVcnmhkVFwcbncjkuQhN+cm9u6tQpIkpk2bdrDLiuYVbOrcxMUlF6MUSiyv1aKIUmOcmPIlA8Gq56oRCNanCiaG6rC3HqDc4qL817851lIOGyJrrBOckqhwyPaGND39L1azJPZ0tnmisEoG0ic/Q2XfJIJt4eX3GSNT0RaPo8uQTu2WjZy5YD5mi4U33niD9vb/eTR0QiOEIAM3rYFPtxSUMVqiuychBIxQW2hztH1h/xnFKURFJxOIUhFSqanpasVTeQLlypBCsPFByJgEk8Ox0f7V3E2V08OdRRmoPuOg+pfNfyFWG8u8uHkAqNRbkCQvid6zCfZ5cGmV9Lc4OKAKceOsPDxOB6ufeYxEh5tpc05BYTAcdxG/CVt2f8iv0q9mttrDnaXhaL1eX/ihQatNobW1FbPZjNn8acSHx/Y8RlFcEVeWXYmvfoBAuxPTgmyUMZ/3X/kvvS0OOutspE9LZm3nALOd1ahCEtPu+Bua7EhukP8SURgnOFk6DalaNf8p0NKvEcirrfxu6u28bw2i0A4gmewc2Bb+B9JrlNx2Zhl12kz6W5ugqICZa9ehF4IXX3wRq9X65YOd4BSoZTZGj6CuN+yUqIzWoPNnYHCOYr4pwO72L1+gnjFvPpIiyEBSMU2JMVTf/kckn+84zPx/IMvwwS1hA4bpPwEh8IYknu3oZ1GCiUWf2Y6yeq3s7t3N+UXn47V5USgUeDybidaNxPdGCHVmNFsb7VgUEuVzMyhPj6F5906kUIiCLgvxl14yRIJ+TdwW/t7cR1LIweMTxx3MKOg7qDCSaWtrI+MQy6WgFKR+oJ7padNRh1RYXq5BadZhGJv0pUO1VoeNQ1Z5XejVSmR7N3EoiJo8+RgJNzyJKIwTHIUQPFWeS18wyO8nR+Ot7meReR4js8L/9Il5H7Jnh3xwO2ZiThwxpRPwKTS89uA/0aemsrCnl2AwyIsvvojH4xlKcb4Vt6WoUEtBLtvfiTskIVQKYs/OJ2XnVSgkLf62e+h3Nn5h/8LSXISkRhObg0+hZY/Lgu3td46jBF/A3jdg62Mw9eZw3m7g7R4r/YEg16cnfq75u/XvIiMzM2Mm3d3dmM1mPJ4mlM3xKKLUxF8xgr5OFy0qiTPGpiFLElVrV6FBkJyeiSYr63hL+I34sG4vG2JGcW2SHpP209WBz9eFQqGhqakPp9N5mMJosbcQkAIUxhXiqxtAcgaIO6cAhebLA0hYOlxootW8va+L6/Ut2KUgyRnD43M6nkQUxjBgrMnAb/PS2KIIstekwFtt4bKRP2CTU01UwVZcoo3OwfwZQgj+ef08dhUuxtHVzpbEaDQVu7jooovo7+/nk08+GVphvgXZaSX8o/YemoNKdtjCcaEM45PRGdPJP/Bb9CLIll3XfWF/jU6FRq1B45PoSJpMf7SB2pdfOF7T/2IqX4fYLFj4ZyAcSPCJtj5KjDpmxEUd1nRjx0bu3XEv09OmUxxbTFNTE1lZif/f3lmHyVXdDfg947IzO+vu2c1uko27K4GggRCCO20pFGgpRfrRFkpbKN7i7i4BEiRO3JNNssm6u++4nu+PWTYJCUWiC/M+zzwzc+65d845u3N/c36K19uOqiuWyAW5uPySgDtAh1oyINFM8cZ1VO7YSmZjO6YpfaOSnssf4A9tOgZb93FV1sGlad2uRrTaeL744gtiYmIOMnYXdQTzi/Wz9MO1tx2hVaLN+P64rYbqbso9HoYGmtFs+xh9AMbd3EfsPMeRkMDoI1yYEIlFpeTvgw00720lxhBDjW4cLr8gOvdLVrxehMcVTGtuMWh46Kbz2ZgwhVaPg0a3g9SICNLS0qiqqjrBMzkCTHGMF0G12rbuYE0UoRBYzsjEWJuGqu5UtN4qyhqXfOclImPNKDWSfoGh+KWWLbjxdXYej9EfHrcNKlZB9uzevFEbu+zstjm5JjnmEDfQB7c8SKo5lQenPEhtTS0ej4eU6GAiQoMxHW2ambY6GwCWBCNalZLavbtRqdRkNLVjnDz5+M7vJ/JxcwetaPi/xvcxmA4OtHO7m1Aoomhvb2fkyJFoe3Yfrc5WHtn6CLH6WJIbIrFvaUSfH41Q/e/bnLXbTUejgw6Fkxn1iwhIyTm/vwNzesYxm19fJSQw+ghhKiXPDUynUi+42eSha3sT45Omss2pICx+N51NdgrX7E84mBplYNxpc/ChpNlswF1cQnJyMo2NjXj6cHoDS9ZE+jlq2NCxPx+QPi8KyxmZ9C8+m0BAycaS/37n+XqDnvAEDVqtHmGciEujonb5CXSx/exm8Lkg//zepuVt3agEnBsXcVDXBlsDJR0lnJd9HmGaMEpKSlAoFKj3BJ0OY6cHPYW27WoBYPa4YExsQ0kRkWotyrAwDMNO/tKrUkqer24i11nDRP2h8TUOZyUuZ3DnlZ29Px3739b9jU53J08MfJjud0pRJ4VhOSvrkPO/zbtP70RKyTD9JuwuB+NURhLGhzL3Ho6QwOhDTIo08WBuCpuiVTxd1sistFk0exVIpY/EbD87llRj79pvxL1iQibtYck0hodRuWkzSUlJSClpbGz8H59ykpM9izNaVrCi08Grda29zWETkjCPzcLYlUWY7bvnp9Vq8fm9nHrVQPTqoKqj8OsVx3zYh6WtLKiOmnATpO43ru61u8gy6DB8K2/Um/veBGBS0iQASoqLSVRGYYtYg0YZgykhGCtQVtKBTSE5c3QyLdWVtFSVY25pwzhhAkKt5mSnoMvGboeHq2rfR0y85aBjXm83Hk8LdXUBUlJSer2j/AE/Gxs3cmHCfMwfOVGEqYm+fOD32i7KyztwltuoDOvCXr6djOYOMiZOPVZT6/OEBEYfY0FiFLkBBRukl3h1HIlhOQAMSngbt9PH2vdLe/tGhWk57/rfEBCCpau+RKMLulJ2nkgVzJGSNpFba99mpr+OO0pqWda2P49U+OmZ4ErBqO7A6bYe9nSdTofL5SK5fyRCZUQTiGNvQxV1hcfZxdbvg09vAqW61432G/bZXeQZdQe1fVjyIS/veZnzss8j05LJ9u3baWltJSW8CnvkblLSLkOhUBMISJytLgImFTq1kpWvPItObyC1qoGwPqKOWlq0CSEDzBk2CzImHXTM4QhmNmhrUzNhwoTe9tLOUpw+J5MbhxBw+oi+YiBKk+Z/fo7X6+ftx3fgxU9eYCVKpYq01i4MI0cc/Un9TAgJjD7IcJOB3eFKXJVdzMi7FoCdnuUMHBVG2dbmg3YZo0cMIjshB58ywPrFywDo7j58sr4+gVqHqt80ntnyO/I0cMu+ajw9gYtCIVDEDwSFn3Vf3HrY07VaLW63G6VaQUyKCXvE6ah9flY/8sDxnAXs/QQqV8PpD4Fpf0CZ1eenxuUh9wCBsa5uHfesv4cJiRO4a+xdlJeX8+knn5JlsqEesJAIy1hSU68B4P7FezF5JIlpZtwOO7V795DcZceg0RI2tW8YvJe22xnuLCd6xEWHHGtrCwahZmSMJ/eA6Otl1cH/7dh6E9qMcNRxxu/9nBXLqwh3SYzZ7VjryhmTlYfeF0CX//POhH0khARGH2RUfDhWtWBlTTsjkmYTkLA1XIun+a8EApK64oPjLcbdEPwFq1v4Nlqttm8LDIA5/8ao0XLX7n/Q7PHxZsP+BIujpt5AoGMYmJayb/VTh5yq1WrxeDwEAgFS8iIxKS24ZTR13e2suefu4zeHzc8Ha14MveSg5vWdQYP1cHPwhufwOvjDqj/Qz9KPh6Y+hN/j59133yXO5CE5/wsMhgzy859CodDw2oYqVi6vRo1g8sRkyrdvIeD3E1lVR9Kjj6CKijp+8/uJtHQ2sUObzAyD7HUCOJDq6o0EAgrGjz+zt628q5yndz7N/Ki5iFYvuv4Rh5z3bVw2L0VLaulUBDA7dmGKiiZ64za02dkow8K+9/xfKiGB0Qc5IzGSDJfkLmlDoVATFpZDjkHDnyOqUCo8NJUeLDAisnMABQqPDa1K0/cFhjkRznqcqfVfMkHr4e6SOupcQUO+Uqkkc+p9+DvTqHM/QnvhtoNO1emCv9zdbjcDJyUiAMW436B2K9i4eytV771z7Mdvb4OqdTB4/iE3xaVt3RiVCsZYggKj1laLzWvjmsHXYFQbKSsrw+VykpO5GqVSz5AhL6BWm6lpd/Cvj/cw268lPFZP+qBotn/6IQaPl8xzz+8z6qgV+zYihYKZaf0Oe9zhKMfjiSAqan8g3huFb6BWqLnGcT4oxfcG6fm8fhY/XQB2H2WpgsZ9u4nvtOOtryfurruO6nx+boQERh/EpFJydUBHgwp2t9qICB9Buk6BXhdGo7GSmq27kb79ORyFQoEpOhqnRo2nw9r3BQZAyliEUPCAez0eKfmydb/XVFZUf95XxoIUlG97Ak/D/lre37hgut1uzFF6MofFYKj18kr6AkCw8+kncO7ceWzHXrYckEFX2gNw+gN81tLJtEgT2h5B0uoIGvZj9cGbYElxCVHh7QTMtWSk34ReH0zX/dLaSsa4VOi8kplXDqBh3x4aKspI77ATfdmlx3Y+RwtbM0trq4j1dTEobfAhh6WUSBpQKvenKO9yd/FJ2Sdcb7wC/7ZOwsYmoAz7btuFDEiWvbyXhtIulpl9pBmb8ft8RBaVEn/XnRjHfG/Bz180IYHRRzltSCIAn+6uxxw+lIDfxr8m3EZhzHY6bFFsePzVg/pHJibRZQwjoqme9vb2Ph3xDYA2DGIHklW7kgy9hiVtBwvBoWmT2WzT0pW4ksqPXiXgCKYz/2aH4XIF62oMnZWK9PgZ549GRCfRYgmj5jfX42tpOXZjr1wNunBIPNjF9cOmDtq9fq5M2h930OIMjiNGH4z4riyvICWqDgVaEtPPA8Dq8vLB5hqGelX0Gx5LTLKelf/8Gyp/gFF/+BPqpO+vAXEy4Nu3mJXhQ5kRFY5Ceah3U0dHC1ptN0Zj0FVWSskjWx/B5Xcxo2sMCpOG8Dn/O3Zi3UdllG5tZtCcNHYIL5EVm9BJiDGasZx33jGZ18+JkMDooyQlhzPGAW+7HZjNkxFCg8m5jfb0MjoTtrKtOI3mRfszslriE3FolKSXF+NxuVix4gS5kh5NEodCQwFnxlhY1W6l2rnf2D8qfhTvdAdQKBJoTnwX64ZgjEp4eDDqt7U1+Ms9PiOcobNSyfWq2CjT6FQpaHfa6P7yq2M37totkDzqIHWUlJJna1sYGKZjvGW/Dv0bgRFtiMZms9Fp7SQsqgpL2BiUymAm43e31GJ0BFD6od+IOL64+bc0eJyMyB9O9Jln0le4v95Bt8rEqSnphz1eWfkcQkgiLEMBeGH3C3xQ8gHXDLgadaUPXf8IxGFK2H6DvcvNjiXV5E1IwJNlJM+6D09dCWkNbST+7a99wuX4RBMSGH2Ya5NiaNYKPtvjICFhLvUN73B2YibLkoOBaM2rFsO+RQCMPus8lAYje6JMRDc1UVlWdiKHfnSIGwiOVq6MECiF4PbiWnyBYE6tnIgcfAhajMNxm6uprXwNKSVxcXGoVCpqa/dntu03IhYBOLQDQa2lOj0J27FKoeK2QnNhUGAcwEOVTRTZXfwmJfag6O5WZyth6jD0Kj1VVVWkpOxG6DuJS5wDgD8geXldBWN6jOR1G95nX2sDuVHxTPzL34/NHI4Bn6z/gP+YxnOprDok2SKA19tBR+frtLakkpg4h5U1K3ls22PMyZjDdZGXI91+9LmRh174ANpqgw4FsfmR3LOokGH2PUTojGTa3IT1kZQpJ5qQwOjDnJafQJpL8lxLB1mZdxAWlssA72oCmloUWmjTjoD3r4bWUswxsUz51S1IpURr7aKlrQ33yZCp9UiIHQBAQsc+7stOYnm7lb+WBdO4h2vDidXHssNpwKIcS1PKGzjqGlCpVCQmJlJZWUmgxx03JsVEWISWkUoz9bGDqNMoaTtWcRnNewEJCfvzH7V6fPy3uolzYi2c963o7hZHC9H6aFwuF2vWPEN6xg7M7RNISJoHwNK9TdS0ORkkNGgNzWxauYh4q5PZ/3jw2Iz/WLBvMZ/W1JDk7+Kfk+cckg5FSklp2YOAh+rqIZjNZp7e+TTp5nTunXAv7qIOUAq02Zb/+TGtPSlT7l5RTFu3ixhvBzFSoEtNDVXT+4Ec0SoJISKFEEuEECU9z4f4swkhhgoh1gsh9gghCoQQFxxw7GUhRIUQYkfPY+iRjOeXhlKp4KowE3sMgk3lDgbnP4NAMj1cYg1rpS1sEsgArA+mysgfPhQUClqEDgmsfe+9Ezr+IyZuYPC5aTeXJUVzQXwkr9e34fAHBUF2ZDaF7fvI6n87UumhZtdLAAwaNIjGxkaWLQv67guFYNCUJKLtkq0MQKlUsik6DGfnMUgH39YTWBkVTGkhpeSesjpcAckt6fEH3Sw7XZ0UtBYQZ4xj27ZtmMP3IDxh9E+6p7ff6xuqmKLS46pzYHRsRUjJjLMvQGWxHP2xHwvqd8D7V7HVMoRRcUmoVIeqhaprnqe+/m3crqmoVGm8Xfw2e9r2cOmAS9EoNbiLO9FmhKPQqv7nR7XW2vCoBTtbrDx4ahIBnxdjRzeanrKuIb6fIxWrtwPLpJTZwLKe99/GAVwmpRwInAo8KoSwHHD8j1LKoT2PHUc4nl8cF49Mw+KV3FpRj80XQWzsqYwzKalU7aWp3okcfAHsfAvsbajUaqISkwlLjiO6oZmvS0ooLi4+0VP46RijwZwMdVuBYO4lV0CypiMY5T0teRplXWWUCy8m31Ca5Id0r69m1KhRjBw5krVr17JpU7CE/MBJSQiVINcXwcC8MTg0ala8+MzRH3NbKQglRASL8pQ43Lzb2MFvU2Pp/63o7qcLnqbV0crFSRezavkSoiIaiFSMwzwuHQgauzeVtjHCpSQmTo2vcgsmrZ646649+uM+Vqz7D0WmbOrVEYywHF4VVV7+KNHRM2loGEd4eDjPFDzDuIRxzMuZR8Dlw9tkR5NmPszFD7iO28e+7c1U4OO+cwaR4m0CwNDQFBIYP4IjFRhnA99YVl8Bzvl2ByllsZSypOd1PdAMHJrkP8RPIkyv5tmkBOrVcOnmUrSmESikA3dUJQE3tGdeG0xut+ZhAKJT0lB3NuB0h2O029nQ143fKaOCRmRgrMVIlFrFX0vrafP4ODPrTCJ1kfx57Z+JGnAxPl0n9es+wV3ayZw5c8jKymLp0qX4fD50RjXZ4+IZ5FFSH8gkpa2Loi3rsR/tXUZbGUSkB1OCAHtsQW+1ed9SRdVaa/mw5ENOSz2NrZ9tISN9E0q1m5QR+11kP9lRz0ybCqXdT5Z9M1aDlvghQw9R6Zy0+H0ESpfym4F/JVKtZE7MwQJDSklZ+cMEAi5SU26kvr4BdYSaTncnc7PnohAKPLVWkKD9HoHx5JPbUXolmePimBbtYcVLzxCOArPHh+mUWcdylj8rjlRgxEkpG3peNwJx/6uzEGI0oAEOtLje16OqekQI8Z01FIUQ1wkhtgghtrQcS5fHPsjkgfH8s1nBDunlLw15BFDQPyv4p23sjILhlwfVUjWbyBg2Elt7K0kzRxPV3EpNXd131sLuEySPhq4a6KhCq1Dw0qB06t0eLt1VDgodj09/nBZHC/ft/hiFwoAjfheO7c0oFApGjx6Nx+PpTfk+7fwcbFoFzY3hJHVYCfj91OwpOHpjtTZB9XqIzultKrQ5UQnIMuz/15dS8qev/4RaoebM6DOxOe3ERrQQEz2bqKhg/qSN5W0se7uIAV4VY85MR7XuPZxqFbFZOYd87EnL1w+wwtCfQmUU9/RLIkl3cPxER+cG6ureJDXlapqaVPj9fqq11agUKsYnjkcGJNYVNaAUaFJM3/kxL72+G1WRFVuClitmxvHhv/6KBgUj9pST/O9/ox848FjP9GfD9woMIcRSIcTuwzzOPrCfDN51vvPOI4RIAF4DrpRSfpOz+A4gFxgFRAJ/+q7zpZTPSilHSilHxsSENijfZv6Mftxa4mG5Q8XrXMGgeCN2dRe7tlTC7PtAoYa9n5I7YTJhUdHYN3xKu8qMV6GgbMdJVNv6x5J7OggFbHkBgNGWMJ4ckMb2bgdPVjczJGYIt4y4hc1N21EYB2CP3oW3MRjIl5GRgVqtZvXq1fj9flQaJcnj4tBJDQFNCkIoaK05ivVDlv0NXF0w5bbepkKbi2yDDs0BRtdNjZsoaC3gpuE34W33IoQfqWsnLGy/MHj5lV2McKnoPzGBvJhWyrXB83PG9ZG03FtehFX383XOpegVgrNiLYd0qal5GbU6kszMP7B9+3Z0eh2ftH/CnIw5hGvDce5uxV3WheXsLBT6w9svNpa00ra2iW6TgpvvGMOupZ/jsloZVdVE1PjxmGefcown+vPiewWGlHKmlHLQYR4LgaYeQfCNQGg+3DWEEGZgEXCXlHLDAddukEHcwEtAKMzyJ6KOM3KZ2si5bQGWilMx4GBf3Hraitw01gUgfQIUf4lSpeasW+6gu6WZuNxgvYS9Dz3Ud3cZEWnBiOk9H/c2zYmxkB+m783LNDd7LlG6KL5qqsSjbsLZUY/0SzQaDbNnz6ayspLy8mBNidNOCQZ+dYdnER5moqXqu0u+/ijsbbDrPRh2CSQNB8AbkGzptjPUbOjtVtNdw21f30aiMZEzs86kuryKWK0fhMRgCI6tsslGvyY/Il7H9Ity2fvFIspjLOSNnUhEfOLRGe+xZN8iWPQHyD6F5uSJxGrUBwlMgEDAS3v7WuLiTqeqqo6ioiKao4I7w2vyg4kWbevrUUXpMI6MP9ynALBiSSV6KZh/xSC0GhVlWzYSFZAYO7uJufF3x3SaP0eOVCX1CXB5z+vLgUMKJAshNMBHwKtSyve/dewbYSMI2j/68E/dE4821cScMhd+lKzr9iMGNeE0dPPl87uRqROhtQjcVhKy+5M5YjSd+4LGYrfTiqe09HuufhKTPBI6q8C1P9p7ZLiR7VYHvoBEr9Lz8NSH2WkNGsOdphLcZZ0ADB48GCEENTU1AERF6nHqBF3mTMwaPQ2lxTitRyGVStVa8Htg8ILepk1dNrp8fmZF7de//3ntn/FLP0/NegphDVBZWUG8MZjmxWDIQErJ0reL0CEYfWYGtYW7WL1nG5E+yazf3nLIx56UfHF70MPt/Jdp8fqJ0Ry6O7DZ9hEIODGFDePDDz8kJiaGzdrNnJ55OhnhGfhtHjyV3eiHxiIU322zcVZYcWkEmQOiKFj2BW11NcTUNZP44L/R5w86lrP8WXKkAuNfwCwhRAkws+c9QoiRQojne/rMByYDVxzGffYNIcQuYBcQDfSdSKOTEG0/C/kdfmICPt6R85kR7WJd4sfY2t00i56Uzc17AZh+xXXBP74/gNVkoutYRjYfa+J6vvjNhb1No8ONOPwBNvXU/h4eN5zkqPF4AoKOzGW0fxJcB41GQ3x8fK/AAEjJjqAzPBNnnR2P08FH9/8Nb08qkZ9MzUZQanvjL1z+AH8trceoVDA5Iqh/b3G0sK15G5fmXUq6Lo0dL64ioHATNagAhUKHwZDJzmU1uPd2sdPgJzXKycIH/47RL5kcl4Za850mwJMHnxs6a6D/6aAx0uL1EaM51JW2syvoyFBVpcJmszF26lg6A51khAd3Wa6iDpCgz/vuYL3Kmm4irAEUSQZKt2xg6XNPkqA1kKkxYJ4VMnT/FI5IYEgp26SUM6SU2T2qq/ae9i1Symt6Xr8upVQf4Drb6z4rpZwupczvUXFdIqW0HfGMfsFo08Mxj4nnrp0emkQCdR7ISN+FJEBBiSXYqSm4iQuPjSdt8DBUXheNkTE0P/U0tnXrTtzgj4T4HoFRu7m36ZTocCLVSp6t3a8lvWvcX/jcFoHTvJfahP/gtwcDF1NTU6mpqcHrDeabyh8Si19tpH9NA+1Z02ksLeGzx+7H7/P9tPF5XVC6NJg7ShU07L7X1M4um5P/5qUSpgrmTfq49GMApiZOoeyljayybmVw/jq8spRBAx/B79Gy6dMKWs0KnMlePvznX9BotYwsrcF0QG2Ik5rOGkD2uhW3eLyH7DCklNTXv4NanclXX20mKyuLQGTQ7JluTgfAVdiGwqxBnXT4VOQt7U7eenALUsCQfB+LH/s3cVn9GFbTStjQk79M7clKKLzxZ4ZheBz5HUEVRpt2KKcnJ1IYv5biLQ52euYF02r3kJiTi3BYcZvD2JuQTvmNNyP7Yr1vc1Iw1cby+6ArGOltUCq4PDGaL1u7KXUEdwcpphR+NfFltjYlY03YRGVxMM4iOzsbn8/Xa8eIzwy6d3ZF5zFh8fvknHMZ5ds2s+TZ//x4W08gAB9cDS37YNz1wSYpebq6hcEmPaf2pMFYUrWE/2z/D1OTp6L/wsnC+lVk5K3BFF5Nbu7fiYk5hT2r6/G6/axQuRlU+RU+j4fRNa0YNTrCzzrriJfxuNBZGXy2pOELSDoOo5IqK38Iu72E4qJ04uLimT9/PlXWoPNBmjkN6QvgKulEnxd5WBdil9PLc/dtxOiW5J6XSe2qdwiLjGJaxgBoaMAwZswh54T4YYQExs8MTYqJSKMWi1fSInJRuCvRTWqnKbKMjV0XIHd/DO3BG2Nq/lA07U2ohaRw4ihcQrL0nS9O7AR+CkLA2U+Cz9mbOwvgquRotArBrftqcPZEfw+MHkiHeRS6zn7Ut38CQHp6Omq1moqKoIE7It6A1qjCOeFcUq3N1OxrY/z5F7Nn1TLWvPXKoZ//v9i7EPZ9BqfcBwOCjoVL27opc7q5vidvlJSSBzY/QF5kHn+x3cCaos3E9ltPVEwpmZm/JynxAvz+AAXLayBOS6PXhqq5jHSbG31dAylPP4U2439naT1p6OjxOotIp83rQ8JBKqnq6hepqnoKtXomtbWJnHrqqWi1Wva178OgMpBgTMBTa0V6/OhyDi2UFPAHePOx7ZjtfizTEpgwxEhLZTk5SWl0PfgQplmzsMwLZaX9qYQExs8MoRBEXTaANEeAmq4I/H4H0xJyKA7fhtevwq5MgrcvASmJTklj1mXXoC7djVIE+HryZNrfegcZCHz/B51sxOQE023sfh8CwR1WjEbNo7mpbOyy8+vCyt7EhDdNuRVFWx4eUYHNVoxKpSI8PJyurmBNDaEQDBifSF2jkoa4gUSvXcrY8xYwaNosNn3yAe31dT9sTFLC2schMhPG/qa3+cvWLsJVSs6IsQCwr30fjfZGrldfTt2GMjoTNpCUvIfk5EtJTwvuStrr7di7POxQ+ZhqbAcpiaqoJunRRzAMH36UFvE40FgQtOWYEijp2fnF9ewwbLZiSkrvIyZ6Nju255GYmERaWlB1taN5B4NjBqNUKHFXBp0QDhfdvXZxBc5KGzujFVw8L5f1H7wNgP6dDzCMGUPig/9GHCZ1eogfRkhg/AzRJIaRn2Rhn9pMGf3IN1kwxQYNog0D/wDNe6ApWBt56ClzmHT2eajqKrCZTSR1VlJ+379O5PB/OuOuDxqXF/0heLMGzomL4B85yXzZ2s0fimqQUhIfFo8zchhKj4lNm65ASj8mkwlrjxcVwJCZKejNGkryrqRffQntrV1MXHAZSpWKnV8t+q4RHEzlaqjfBuNuAMX+m9SmLjsjzUZUCkFABnh8++OohIrs2gTW6ouJiWtApYokJ/vuXpXLN5lWy31eMq0VKAIBMi6+FNO0aUdp8Y4D3fVQ8C7kzwOFghdrW7GolL1G/+aWLwFBff1U2ts7mTRpEkII2pxtlHSWMCw2aHvwVHWjitYfUijJanWz6csqqtUBfnPdUNa/9zq7V3xFVpuVqPRMkp/4LwptH3AMOIkJCYyfKX8cnEqcUPIAf6a6rYZfT7kSgFU2JSCg6PPevmPPW8DQUWNASlbnD8P9xuv4eupF9ClGXgXjb4StL0Hjrt7mK5OiuTU9nnca2/lneTAxwbg556OoOAtJE1VVHxwiMIzhWqZdkosPPe0xw1n42KsYLREk5Q78YdHf9jb48LqgfWXoRb3N7V4fJQ43o8OD6ci3NG5hTd0a/pR3K74KK22ym4iIdiIiRiLE/q9na60NpVpBjcNOZNkOzB4/0ZdffsjHnrQ42uH184JBlhNvodvnZ0lbNxckRGLsMfq3tizBbBrKli3FDBkyhLy8POxeOzcuvxGVUDEjdQbSF8Bd1oU28+A0Ij6Pnzcf3IraJxl3VgaBgpVs/OhdUrudDFLqSXnu2VCt7qNASGD8TInTqnljYAZODLzWZmF4xmD8Ki97K+vxRvcLqgZ6EEIw++pfown48EeZEEhalyw7gaM/AkYEBSMNOw5q/kN6HAviI3mipplqpxu93kDM5Lmo7XGUFP0HkykMq9Xam/IcIG1QFHGZZopyLiB65QparC6S+g+gpaYKt8PO/2TTM2BtgAvfArW+t3lFT2XAiRHBm9eKmhVEBixMWZ1Dl9KFWtuFEK2Eh4846HKttVbMcXoGtxTjUEriBw9FFfm/6z+cNHhd8OYFwcSLC96A6GyWt3XjlZLTe4z+Llc9VtseYCg+n48hQ4bg9ru5aflNFLYV8uCUB+kf2R9XWWfQfjEgqvfyfn+Aj5/cibfJSUGSimxtFatee4FElAyxeUl94QVUUVHfMbgQP4aQwPgZkxNvZrK/gmUiH5/XT0SGlpjWdP5l0kNH5UF9hUKBJSwMv1JJjTGa9iefwtvQcPgLn8xEZIAmDBoPjgEVQvCnzHgE8HJdGwB5A4ehbZyGQl1PjXsNgUDgoNK1QghmXTkQqVCj08azZulmkvMGgpRs//zT7x5DzWZY+xjknnFQ3QuAz1q6iNWoGGY2sLNlJx+UfMCt9qvwt7lxTjCSnLwHIVTExZ7ee47fH6Cp0oo23sD4ts14VUpSJvWhgj/bXoHaTXDus5A5FYDX69uI16gZ0bPTamlZAkBzcyIajYaklCRuW3UbGxs3cu+Ee5mWGlS9uQrbEBoFuixL7+XXvltC075Ovjb5ufWKAax85TkSM7PJLygm8pJL0CT3jRK1fYGQwPiZMyksgEMY2ba3lBFjczC5o9jQGY+9s7JXz/8NcXGxSKWKJ0adS8Bmpfqqq/G1tZ2Ygf9UFIpgFHHNxqBL6wEkaDVMijCxuLWz1z02NeY0ACqsKwFo+9Z8w2P0hIWr6QrPouDtT/DGZNB/3CTWvfcmnU2Nhx/DusdBa4IzHz+o+cnqZj5v7eLChChKO0u4fun15MtchjVk4xqgY3f9MyQklpCYeCE6XULveW21NnxuP56qr5EGB3H6cAbNnH0Ei3Qc6ayG1Q9ByhgYOBeAj5s6WNNp47qUGJQ9NpqW1qUYDP2oqnKRkpLCvRvvZXnNcm4ffTtnZgXLzMqAxFnYjq5/JEIdvHV5PX72rGtgl8bHsKnJ1C35AJfNyiC0KCWYZkw/MfP+mRISGD9zJqQE8+x8XVJB1uBodNGC6SWXsS2gAOfBqbszsoPJ7eK17Wy49i68DQ00/bMPGsAHzQuqpDY/f8ih06LDqXR6+LI1qBoyp2Wj8BpJU/nR6DR88skn+P3+g85JyImkPXoAg5squfrVrUy+5GoUSgVbPv3w0M/2OKB0GeSdCcb9apB9dif3lNVzVqyF2zLiuWP1HaT6Evhb5a9Br2KF7RNSU9cSbp5MTvZdvecFApLtX1WDANfur1D5Asy6/z8oFH3E02f5feCxwxmPANDl9XFrUQ2jw41cmRQNgNfbRWfnRsLDJ9Pc3Iw2WsvCsoVcm38tF+dd3Hup7mXVBKwe9PnRvW1Vu9oIeAOUagOMtu5gx5efMXTiNFQfLcRy4QK0/fod3/n+zAkJjJ85OVFZxMpGPtdr8ZZ0MP3yPHQ+I1scZ0PDzoP6Dh4zDqUQpIgOlhfuRXnKadiWLyfQ10q5jr4WYnKh5MtDDp0XF8EAo467SoI1vfUDo9G4U8lR6cgamUlrayu7dx+szho+Ow1UGtwxE7HWNlDqUDJgygx2r1xyaL2MT28Crz0otA7gs+YuBHBfdhI13VXUtlZzT9VvUQQEHdM1GM3rUCh0DBnyKArF/riEdR+WUrq1mUxNIV1KL57wFOLi+ojtwu+F4s+DwrOnOuLrDe3Y/AH+mZOMXhm8/bS2rUBKPzu2g1KppNPcCcBFefudBXxdbqwrazAMjekVGC3VVr56pZA2RYCpoyLY/dn7ZI8Zz/CEoCtu5CWXHMfJ/jIICYyfOTpdAnPElxQaInm7opmM7HgcqXVoWs/h9Tdeg9aS3r4qlYoBgwYRsEQztGs7a9Q6Ag4Hjs1bTuAMfgJCQOo4qNnUG5PxDUaVkrlxEdS5vXT7/Cg0SqJSJuA1V6FtqCExMZHPPvuM6urq3nOik8MYPNZCW1Q+E9rreGNDNUNPOR2/10vlzm37L96wE3a9C5NuDWYH7qHF4+WthjZGhRuJVqt4ftfznNExBb1NReSleazbtRmLpYPo6Kmo1fu9f7rbnOxaXkt6bCc1FQvxKZSM/9X1x27djjar7g+mc8/bH4W+qr2bAUYdA8P2OwK0tHyJUhlJcbGHU045hQJXAWnmNKL1QcEgvQE63isGCeZT0hFC0N5g55PHd2ALBNiVoSSv7HP8Ph8TF1yGc/MWlBYLmszM4z7lnzshgfEzRwgFC+L0DJS7uDvCx2c76rjh9+fTFVNDZ/1FlD7x54MM4NOmTUNnMGBN6U9r2Ra8SgXuvljGNW0CuLuDBYu+RbYhWAr1m5QhmQOvBaki0vgVmkESs9nMG2+8QcMBRv8hZw8CGWCMxsgH22rZ3KVFpdXSXFm+/8KrHwatGSYcnDb7kcomWjw+/pKVyH+2/4fygkIuaz8TXf8INlbvpKGhAa3WjU57cJruHUtqQIBz24tYdRrCzvo1E8YcbEQ/adn6Mnz9bxh+GfQP2ol8AcmWbgdjLfvdW2tqXqGl5Svq6lKwWCKoMFWwqnYVU5OnAiB9Adre2Iu7tJOI87JRRepw2b188th2rG4fb+kczLavpHLHFmZecz3K7Tvp+uQTwqZP7zuVB/sQIYHxCyAn/Vp+z79I83VyT1MLao2WARdH0Gao5+uWc/G/fHZvDqbIyEimTp2KUqPGb7LQHB+Du7zsez7hJCR3DhiiYMU/g6qRA8g2BoO3SnqSD2o00eTE34M3vIL4+veZde4sNBoNixYt6jWOG8J1RIlWPDKW7Ag9jy0vJSolnebKnrWp+BoKF8Koa0C3f5cQkJLPW7uYEWUmXtnJ+k0rua/uRrRRYVjOz2HDhg3k9E8HnGi0sb3ntVRbKVxbT3Kggjalh251JJfN7yOGbq8LVvwjKLTPeDS44wNea2jD4Q/0Cgy7vZzikntQqUZQWjKIiXMm8o/N/2By8mRuGn4T0i9pf6cI1752LOf0wzgiWNCzYEUt9k4Pb2vsXGnYQtferUy97FoyFFrqb/sThhEjiP+/P5+o2f+sCQmMXwAGQwapsdOZq3yVag3cs6+GAXG5bE5ZjNMXw+q6M5GvnBUsIQoMGzaM6LhEXAnp7ImJoKsv1srQGGHmX6FqTTCA7gDVVJpOi04h+Li5ozddSMqg+cTKK1BHlrO94DUmT55MbW0tW7bsV8cNGmrAobZwSYeP8iYbFTKcpvIyPE4HfHw9RGcfsrtY3WGjwe1lVqSe/yx+iL9W/xp1uJ6Ya/Npd3TidDrJyQ4KCq1mvzF32at70WkhfOsL2HQavLnjMBymbsRJyfbXwNYEU2/vjXBf3NLJncW1zIwyc1pP7EVXV1CdV1k5ksjIGEr9pUgkt4++HbVSTednZTh3tRJ+egZhY4NeYx6Xj4LlNXRalIxxr8NbtIWJCy5j2PRTaPjzn9H170/y00+j0OsPP7YQR0RIYPxCSIify3DxNWe1NPBsUzseVSKN0aV48xvZY5vOmuqZyFfPAXsbarWaiy6Yh1QosMXEs9rVSeCnpvY+kQy/DGbdC3s+hMV/7G1WKQR/zkpkRbuVPxTtr4ORN/EWFG4z0c6NDBs2jOzsbBYtWsT27dsBGHjVqQxs+QJbp4rrY4x87krG63JStOi1YF3xMb8C/cEJ8R6taiROo2Ld1n9y2c5TUBu1xF83DKVJw549wfQssbFBFZlGExQcnU0O2mptpNm2UhpnwC00zDj7dPoEHVVBVVTyaEifBARVUX8rrWdgmJ7nB6aj7il41G3djZRaKsrtjBs3jm3N24g1xJIcloyUEsf2ZgxDYzBNSgaCac/XfViG2+Gj3LqR1JYCxsy9gNHnnE/zQw/jb28n7q47UYYZT9j0f+4ckcAQQkQKIZYIIUp6ng9NHxns5z+geNInB7RnCCE2CiFKhRDv9FTnC3EMiIycgFpl4jzzs+j9kpeLm8m0ZLIv+2uGTE+hwDabdRVjkcvu7ekfiTY2A09ELF0GHZWLf2D+pJONCb8LpgzZ9kowPUUP1yTHcGNqLO80trOj2wGASmdEGZiJwlLBtu1PMH/+fLKysli4cCEFBQUIjYax/7oOrbuDlMomPJEptBkT6N7a416bdnA97Y2dNtZ32hmsKCZvbxSmgIGU60ahsmipq6tj1apV5OXlodUGgwW12tiem2IpUkpqqr6kw6DFNvQ0ZgxOOz7rdaSsfhDcNjjzURACv5TcUlRNlcvDbRnx6Ho8owKBAFVVq+nuNjN9+gwc8Q6WVC9hfOJ4hBD4211Ilx/NASlAqve0s+frOlypgrSOzRjScxk//2JaHn6YjtdfJ+KySzGMGPEdAwtxNDjSHcbtwDIpZTawrOf94XAeUDzpwMT99wOPSCn7AR3A1Uc4nhDfgUKhZUDev1FrC8mW5Wyt62CoZhBl3WVMOL8fg6YkscN2Jhu3Rvbq7YeMHAtC4I2IY++SxSd4BkfAsEsh4DsofxbA79LiMCkVvFjX0ts2dMIf0XVk0939H7q61nDBBReQkpLC4sWLkVKiy8khJdJOizuCxyLasBmNDFduwW9OhZj+B11/YXMnBoWClMINnN0xjbBRCahjgvW7V61ahV6v55xzzsFmDzoVaDQxNFdZqdjZSmJgFS1mDZvNI8iZNPMYL9BRpG47pI7tdaN9pLKJ9xo7uC0jnlN6VFGBQKDHPtRAePgAkockc8uKW8iJyOGPo4I7QU99MNmiJjFo73DZvaz7sBQMSmqL3sYgPZx99TV0ffABbc89j+XCBcTdcccJmPAviyMVGGcD3xQIeIVgXe4fRE8d7+nAN3W+f9T5IX48MTGzyMn5C6nKAkqNgmHdA2i0N2L32pl8QQ4D0mrY2jSR8m3BKnUT8zOpkpF4I2OpbGn48cWDThYSh4EpAcoOzo9lUik5LSacL1u78fREhZstsahrr0Zpj6Oo+B5UKgUDBgzA5XL1pg0Z8/szQSioW17P3ZZP8EkFC03X9Rp3v6HA6iBTG2Bu5VhskV4sZ2UBUF9fT3FxMePGjaO9fTGVlU8QFTkZtTqC+uJgFHpLy2b0Ki0bI0cyKOngRHsnLV4XtOyFxKEANLm9PFXTzBkx4fw+fb8H2JIlS9ixYwNqtZuszNE8s/MZlAolT8x4ArPGTMDjx7qiBqFRoo434vP6+fTxHXQ2O9hEGcmuOqZfdjVxCUm0PvEk+mHDiP+//wt5RR0HjlRgxEkpv/E9bATivqOfTgixRQixQQhxTk9bFNAppfxGOV4LfGfSFyHEdT3X2NLS0vJd3UJ8D4kJ88lRdeJVKPDag3+u0s5ShEIwZbqPCGUtGxeW4HH6CNer0cX3QyqVWMPM1O/bc4JH/xMRAtInQuWaQ9KhnBMbQZfPz59L6gj0HAukm0kouQCXq5rGpo+xWCwAdHZ2AmBJimDs2el0x2YSrWxjW0cyizbVUt+5Pw+VLyDZY3NibK4iwRtD3Gn9Earg123VqlXodDrSM5oo3PtHIiLGkZ//JFJCRUELOmUpNq0SW9JwdBo1AxIPrftwUlK/LbiTSxhCs9vLvB2lSOC2jP1pTpqbm1m/fj3DhgVVbFap4YvKL1iQu6A37sK+oQFvvZ3IBcE1q9rVRnOVFeWYKKJb16ExRzBwzERqrrkWX2srsX/4PUIRMsceD753lYUQS4UQuw/zOPvAfjL48/O7foKmSSlHAhcBjwohsn7sQKWUz0opR0opR8bExPzY00P0oFCoGBoTTJfQ6PAz0NuPt/a9FTwWn8dE8wt0tbpZ+2HQM+qSWSPx+yTeqARWv/nqCRv3EZM+Mei501J0UPO0SBM3psbyan0btxfXIqXEkpOAsWUoCplKZeUThIcH1SLfCAyA4XP6MXZk8L29U0eyvZYX11T0Hi+0O3EGJFOqw+iKdGEZlAjAzp07KSoqYvQYQUnJnUREjGXI4GcRaFn6UiENpV2IttVo/JLnxCAuHZfWN7yjAgH4+kHQWSBzGveVN1Dr8vDm4ExyjEGjvs1m4/3330ej0TB0aNCQvbx+J2qFmssHBFO1u8o66V5ShTbbgr4nI23p1mbUBhXvbd9IoruRCWeeQ/1vfoNzzx6SHnkYw8iRJ2TKv0S+V2BIKWdKKQcd5rEQaBJCJAD0PDd/xzXqep7LgZXAMKANsAghvvk2JAM/sJRZiCNheNJMhAywJ2MLd7Rfxufln1PeVQ5JI0kNryAjppbq3W1IKZmYHUv+kDH49UYqmptxWrtP9PB/Gv1mBZ/3fnJQsxCCOzMTuKFHaCxrt5KWlU2X0oa+ajZOZzVud1CVdaDAAMiO2gtAl68fZl8XFRtX9x5b1NKFQkomtAZIuWg4Qgi2b9/ORx99RL9+8SgUbxAePpwhg59DqdSz+p0SSjY3kaXcTnegnQZ1AkPSY/jdjOxjtyZHkzUPBVV+U2/HrQnj89ZOzoqN6I25CAQCvPnmm7S3t7NgwQIkwXorX9ZtZUryFKL0UbjKOml7eQ/KCB2R84P2oK4WJ+XbW+iKUTG0fRMGSwTmN97BtaeQ5EcfwTxr1gmb8i+RI93HfQJ8U8XlcmDhtzsIISKEENqe19HABKCwZ0eyApj3v84PcfSJNueRoAlQo9Viy36Sma6h/N+a/8MhfZB7Bkne5dg63HS3BlUs5887DZXXh99gYsUrb53g0f9EwpOC6UJ2H5owUAjBbRnxWFRKPm7qQK/RszJhG0nF4zGrhlFR+U/iE+pob9/vZUXlGrQ7nqZeO432iIsxuyCv+FN2rlhKkd3Fi1X1jGrzY8u1Yk6OYseOHSxcuJCsrCxGj+7E73eQ2/8elEo9bqePwnX1pCoqqa75goBSzcZ+p/DyVaMJ0/aB3YWUsO1VyJxGYPSvuKO4lm5fgLlxlt4ue/bsob6+njPPPJPMzEyczmoQGmqcnZyacSoBt4/2N/eijNARc10+SlPQYXLL55UIhaDMVUS8s4GBWhPePXtJfuxRTDP7kDPAz4QjFRj/AmYJIUqAmT3vEUKMFEJ8kyo0D9gihNhJUED8S0pZ2HPsT8DvhRClBG0aLxzheEL8QLLDIujWj8VtqmZuUg1lbQV8WvYp9JtJsmIzALX7gon1hBCkZ+fgN5hp/ux9dlf1sZTn3zDw3KBRtnnvIYc0CgVnxlr4uLmDT5s7qchpozysntgl1xGmHEC/fitpbPwyWGDJY4cv7wJTItE3vIbREobWfDZqt+CtD95j7rZilO4A15d2MfHsYFqMZcuWkZKSwnnnnUZ9wxvExZ5OWFjwV3Th6noCPomv6H2sei3LYqczadTAviEsIFh2tbMa8s/nvzUtvNnQzu/T45jSU3rV7/ezcuVKYmNjyc/PB8BuK8GKCb3KwITECXQtqiBg9xF5fk5v6dXOJgdFGxrJHK4lvWghCn04kStWEzH/fEwzZpyw6f6SOSKBIaVsk1LOkFJm96iu2nvat0gpr+l5vU5KmS+lHNLz/MIB55dLKUdLKftJKc+XUvaxtKh9lxyjlmK3BrfxUby6eu6MUbGs4iNk2kQsyjoMOi91xZ29/QcPH4pUq+mItvDhE28RCPRBj6kBZwdLhK66/5BaGQB3ZyUy3Gzk14WV6CIGcXvSI+iSYon/6nqUIoHo6I3BIL6v/x2sWHja/WhMJkaenoE1LIt0q54PT7kIhd3L85tcGEf40Or1dHd3Y7VaGThwIA7HLvx+B0lJFwJBlcu6j0oxO3dSHqWgw5JOY1R/Lh+ffpwX5yey4034+NfBNCCDzuWzlk5GmY3clpHQ67VUUFBAW1sb06ZNQ9FjnO6w7mafrZuZqTNRVHmwb2okbHISmpSgkJEByfqPy1AooKryCxQywOSdezGkpxN9440nbLq/dEKuBb9QbkyNI1Kt4nVDDqnlt2NUO5mq2MIDux5FJg8nSVNATWEbto6gDO/fvz9KhQJ7XCKKok3c/+W+EzyDn4ApDqbeCXs+goK3Dz2sUvJKfgZKBNWiPzaFg85ZahQ+HYmaszCZ2/h69evIqnWQPAoGBEOK8sYnYDIreeuMq+k2hXNPgZN3LS/Tf+JwAOrqgqa5pKQkursLAAUmU/CXds3edmTAi6vjS9RqNe+GT+eGGf3JiO4D0coVq4MpUTImw8Xv04maXVYnkyP3Jxf0+XysWrWKxMREcnNzAfB6O5C+TtoDOm4fczuOHc0IrZLwWUHPKSkly1/fR/n2FqLSqugu2kpOYxuWtDRSX30VVcRh44NDHAdCAuMXSqxWzexoMxu67ET0m07K1luJUatIs77LkoFTGaJ+G7/byUcPbaWrxYlWq2Xy5Mn4TBEoE1Ss/vwLqtscJ3oaP57Jt0LCUFjyF2g9NEdWhFrF9CgTGx0m0KTzduN7oBREWqejUETQP3spsn4nJO2PKFaqFOjOTmfl0DjOqvVQ6v6QQlMJMYagN19xcTFKpZK4uDg6u7ZgNGahUhmRUlJZ0IJ0rKBbp8Q1+FR8Si1nDE44ZFwnHW4bfHUXmBNhwVugMfBeYwcSmB653w14/fr1dHZ2Mv2A7LGdncH8XEKbhlljxl3Sga5/BEIdzDtVu7eDfesaGHFqGmXV21F6IbvbSdrzz4WExQkmJDB+wUyKMGH3ByjIDsPoGEBm4Z3EqCXFro3EjZvM2eF34nZ4+fDBrbTX25k8ZQoJErxR8UxrWcGTb/TBdCFCwNxnwOcKprE4DHdnJaFTKhEJf+Cj8oUoIjWIFh1Jib8m1dqBwu86SGAAbIwUaH2Sm/c5eTdhGdE1AaSUtLa2smPHDkaOHElT01t0dKwjNuZUpJSs/6iMip0VeNx7SE/P4fnuVM4fkUKsWXc8VuKn4+yA186Bxl1w2v2gMbDT6uDflQ1MsIQx3GxASsnq1atZtmwZeXl5ZGXt96RvbFyIPaBAbxpMwO3H3+VBnbB/R1W0sRGNTkn/idGom8pI6ewk4dY/oIqOPsxgQhxPQgLjF8z0KDNxGhUPt7QTfW0++vZsVNYMor0lODImEKcuZe5FGpDw0UPbaKm2csoZpxNQa5AR8ejXf0BBxXfUtT6Zic2FfjOhbMUhgXwAmQYtd2Ym0CwtdJnm0qrvwtfsID4sm7xiKy3aaKxJk3r7f9XaxTtN7cxo9dMS6MKtDhDfoqGprJQVK1agUqkYPbof5RWPExkxkYyM39FY3s32r6rRdn2KQkhWZp8BAm6aeZK70dqa4eUzgsWi5r8arKYH/KOsAb1CwaN5qUAwmnvZsmXk5+czb9683t1Fff17NLd8zgabgrTwTHw9nniq6GDKlK1fVFK0sZHM0XE8+afbQYBl3AwiL774MIMJcbwJCYxfMAalglsz4tncbWelLkD4aRnElp5JjCrANvunAETJQs7943DUOiWfPr6T1GEjGJqTgyM2EZ1RzZv3P0CbrQ/6KmROBVsj7Dv8Lml+fCQXxUfiDD+LTyJq8Ld2oH/3PoSE9YmpvPrW+wQCARz+AHeW1JKt13LbbiebIjcT5YgjuVnPe8+9wd69exk5Mom9+65ASh/Z2XcihILijY0ohB+XvwFdci6flrm4aUY2iZaTPC33kruhrQwueqdXWDS6vazusHJRQhQpOg2ff/4569atY9SoUcydOxelcn/98eqal7ApolnUpSYnIgdfS1CtqY7RU7W7jQ0fl5M5Iob/tDajtdaS3G5l6h23nZCphjiUkMD4hXNhfBQJWjUfNHVgGBGHOXIy5rpJOO2b8OvNUL+N8BgDE8/PxmX30ljexVkLFhAfGYk3OpHo9hIueGYdLq//+z/sZGLgXIjPh4XXB3MgfQuFEPwtOwktbl6xKIkO+xeqzs00jJqGMaUeu6OYyspKrtxVQZ3Lyx1uHWF+2GUqYUbxlRg8AmtXDUZjE1rdY0jpY8Twt3tdaSt3tRLlL8GrUrJJncrwVAu/ndbveK/CjyMQgNKlQUGRNb23+fGqJoSACxIiqa6uZtOmTYwePZo5c+b0ekUBdHRuw24v4ou2Li4ZcDnjEsfhqbWBAAfw9dtFmGP0FKdpaSsqQghJVHRsKF35SURIYPzCUSkEg8L0lNhdCIXAkp+IpX4SCumhcEgKgV3vQWcNyf0jEApBdWE7CoWCyTNn4tPp8YeZMO/dxMvrKk/0VH4cOjPMuidYc7ro8Jl4TSolow02wohB69uCVVxM1PSn0GgiGTLkK14qXMOqDiv3picwYEUD2437yMkfTKo+HRl1IbpMJfn5S1BgYMTwdzGZ8gCwdbixdbgJtG4FoMBj4bwRycdt6j+Zpl1gbzlIWDj9Ad5saGN+fCTpei1bt25Fr9czc+bMg5IBSinZuPs2rH4YnvVbbh15K9Lmw76xAUU/Cx8+sh23w8fIC/qxeNFa7i54DYCUefOP+zRDfDchgRGCfgYt5U43filRReswdOawpSmJZk0Txelq2PYKGr2KxGwLZVubkVKSk5ODTqvFZ47i7PolfLRiT9+LzciYAuGpsPbRw8ZlAFySnMrUjmABJadrNCp3JCNHvI9KFcZGTYA4pYIz1rQinT5eiP2Qc3PP4YwbhuAy++mXtwWvU0XVimEYDPvrWTSWd+H3FFGvakSlMWLTRXFGfuLxmPGRset9UKgge386jg2dNlwByZkxFgBqampIS0tDozm4tM3msqdReyoolFlcM+QGhBA4tjcjvQFW7ulACMHcW4fzxZcr+Pvy/+A3qAFImDL1eM0uxA8gJDBCkG3U4Q5IalweVFFBHXqcZx4bbSoa4g34d74G3fXkjo2nq8VJyeYmVCoV/XNzITKaFpOOs9a/xgebq07wTH4kCiXMuDtowP3wWvAdaouZrVXx17InqNZE4ZXpeGus6PVJJKVeSbGqPyNrrfj2tLMoawMiXkdeZB6RCUZMWVswGrvwf6GnaW8VpTXBDMvNVd189dwbeO2LsNjdfBI2jTlDkgjvuUGetPh9UPAOZM8GY9BbyRuQPFvbglYhGGsJw263097eTnLywbulbutuOqseotGn4apxLyGEwNfhwraunm6FwKtTct5tI+iuK2faC/fit0TQPKg/pugYTJFRJ2K2Ib6DkMAIQZ4xKCSWt3WjCFMjNApmaCax3q4koAhQmOxGfnoT/UbEEpdhZslLhexcVkO/fv3wBiRqcwTSaGXdw4/x9qbqEzybH0n+vGDt793vw2vnBl1GD0C34xXC/E5uHHIHDoWL8m178AYkT7ln4hJ6ZjRIWscpeFLzOqekn4IQgr179xAZvw2vK4zwQiMCyTufrqCxvIv3/vkhzo5lxCrDyGpyYMgbyD/PzT8xc/8xlC0PZvsdelFv05K2Lla0W7kjIwGDUsGOHTsASE9P7+0jpWT7nttxBCS2mGuJNyUhpaTtnSI8XW52dHmZeH42YRFaav7+D7xKNXWnT6OltprJF10RSlt+khH6a4RgqEnPOIuRf1U0sL7Tjn5AFGKnjdnqK/msU01zlJLG7q9RuZo4+5ZhZA6JYc17JbTsEmi1WkyjJyNUKlIDxbz65qfUdvShgD4hYOItcO7zULMRXjkL/N7gsYadsOVFChMmUmkZR1F4Lf4SK3/et493mh1c3dzNKHc571lfQCKZlDQJp9NKUfHNREQ00L7vNEynXwtS0rZpPSve34fHtgKjUsPw7TtZlDqW2+fkoVMr//cYTzRSwvr/giEask/pbd7YaUenEFyVHM2uXbtYvnw52dnZB+0wKurex+fYyzpXLOflXgaAu7wLb2U3exx+hl7Un6xhsbR8tZSYop2sn3A6lTs2MuL0c8idMOW4TzXE/yYkMEIghODxvDTiNGou2FnG8skxKMLUXOA4jbDY86h0KyjMNlK39reoNUpmXzeIITNS2Pt1M3GaXKrr6jCMmoLR42VG/efcee+TdDm9J3paP47B58N5zwVzRK38V/Am+dWfQaWjbPJfaPL40I4fSpgvnLfqOxhnCvDbMg1uYytbxSbi9NHkReaxaPEtmM0VRFiux99xNoXWLAweP0luaNz9GQFvG7mlVSwdO5dNY89gfFYfULlUroaKVTDlNlDtt01s6rIzxGRgw5o1fPDBByQlJTF37tyDTt1c+iTtPsG1E17uLZDUurQar5RETUthwIREXN02Sv76D6rDYknMD1bmG37aWYQ4+QgJjBAApOg0fDY8m1HhRm4ursExIgb33g7+lP4HPnFkUOJRsU9bQPWS81EQYOL52Uy6IBtnSTj5mWOpdjhwD59AlNPLkLqVPPXYMyd6Sj+eAefAkAuDEeA734KKr2H0tYzKGAxAUVICdwzX41EaaN33IoFuL3XhMdT5BKeblaxd8xlm89eo1aMYPvwPTLskF3uXh4AxC6VKTcC9nTC7gjC0PBYzluum9OsbZUX3fgYqPQy/rLep3uVhp9VBUlcry5cvJz8/n8suuwyDwdDbp7C1EK23moCuH9mR/ZEBSfvHpVDRRb0QDJ+Tjre5mYLzFhDe0UTnxZdTs3YJAydPxxwTeyJmGuJ7CAmMEL2Eq1U80D8Zn4RF2XoUBhXW10t5cugzLPUOpMiloCiwlcD7l4OUDJ6WQnymGWdJOPPPuwCrSoUnPYdwdwBfwdc4XH1slyEEnP4wKLWw4h+gMcGwy0jSaRhqMvBSYzurolXcWOLm0dKgp9B7zi9IlkYSu3zU1T+OQiEYOeIBAJL7RzDpghx86nz83jKiA2FMKC3luexTGJgSyQWjUk7kbH8Yfh8Ufw6ZU0C9P6jw9YY2AoB+81ry8/M599xzUan2p2Pvcnfx+MbbMSlhZPoCAJx7WnFsaKDU5SduXg4qtYJ1f/wr6vpqPp13I7KzCJVGzaSLrjjOkwzxQwkJjBAH0c+gY7wljDdbOom8YiAyIOGVep7PfpI23QgUasFK+TWBqjUAjDgtne42F9vf72TI4OE0RkeT1N6F3u/gnhcXIQ+TeuOkRmOAuIHQVRNMVGgK1j2fFx9BvdtLll7Lr2IiiXVF8EX4WqqjWzhXeTE2WySxsZWkpV2DwZDae7n+Y+NRqs0g3cQ2VfPlRbfyZcoofj0lE6XiJN9dSBlM5d5ZDcMu6W2ud3l4qrqFEX4X4S4Hp5xyyiE7pad2PkUeRSC0JMfNAaDlqyocAYk3P5qkwVH85cnPsWxeTfGwKQxPl9QX72Xm1ddjtIQSDJ6shARGiEO4NDGKKpeH5boAcTcMRRWpw/FBFbeNepGv7UZkjJrtRTfh9XaRnh/NWb8bQlezE9luJiAl1tlzUPv8hH/9Cq++98WJns6PR/ZErbttvU3enhgTdyAAvmDMxhsxi/AFfCgCPlLTduHzqfB5bQdfKwAE7MHLSkmtKljvwes/fNzHSYOU8NktsOpfMGge5J7Re+ilulbcgQBDdm0iNzcXk8l0yOnlLesYpPeRkf4btNpY6pdXo2xx0mxQkzc3k/OfXsekl/6F0OuZdds1FK9ZQd7EqeRNmnY8ZxniR3JEAkMIESmEWCKEKOl5PuSngRBimhBixwEPlxDinJ5jLwshKg44NvRIxhPi6HBGjIX+Rh3/V1KHy6AiYn5/AnYv7s2teC1n8F6bni5lJ8WFdyKlJDk3ksxhMdTv8DEgZzCFXi/KuAwMAUnLB0+wa+PGEz2lH46zA5oKIToH1j0G7RVIKXmroZ0sg5b+VQ4c25pZFbEVi8/EoPZMhFyJQhGgrS2Zuvo36Ozc2Xu5nctr8PuDpV2LUnJY3+Agzt3NI0tLTu50Krs/gK0vwbgb4Nznguo6YGOnjZfrWpmgV6Hpau+toHcgNmcjIxX7CKAgKelCAh4/zqXV2IDAWWmc/cRaKC0l2daC9toreO/Jhwj4A4w4/ZzjO8cQP5oj3WHcDiyTUmYDy3reH4SUcoWUcqiUcigwnWDamK8O6PLHb45LKXcc4XhCHAXUCsG/c5Kpc3t5tKoJTWIY2mwLtnX1TDdMYq1DYGjw0tj2BRWl/wZgzFmZ6I1q2tZFMHncTFpjYzHrw/GgZenbb/UN1ZTPA6/Pg4APZv8z+Ct703MUO9wUO1xcHRvJvbudFOmqeD7xM37TPJ854RmkJBfSLfuTl3svXo+OLVtuwufzULi2nvUflaFxl6L2SZ5JOpMOvZkbd31IU1MHT644tB7HSYGzA764AxKHBdOn9MRCtHl8/LqwimiNitlNFahUqoPSlgP4fA7WbDqTVI0fYi5Hq4mmYXkN2oCkKMnIVe/vIFbl50Hbemw6DZ+v/gqlWs2F9/6b2PTMEzHbED+CIxUYZwOv9Lx+BTjne/rPAz6XUvYhR/1fJqMtYZwVa+GV+lbsPj/hp2YAkPuxiYndw9ibfAnRbR5qq15Eep1Y4gycf/soBAJNdxzjxo2jKiODNLuLQH0pa9565Xs+8QTj98Lnt0HdFjjvecieCQPPgU3P8kXhBgCit29D4xc8kbaCQOZfSYqORhX7Kg6nmf80tdB/0FAkCxCKGlYsvZw17xaTmG4g4KqhW2HGKJWcX/c+4Z5aHtv9Jh8s343D4zuh0z4sm54HezOc8WgwGh7YY3NyypYi2jw+/hZjpHb7VkaPHn1QChCn18o7X89G7W9nsxjDlAG30VprpXlVDS4Jf6prYHy/aP676zXkhnU0zJwMQnDhvQ+GhEUf4UgFRpyUsqHndSMQ9z39FwBvfavtPiFEgRDiESGE9rtOFEJcJ4TYIoTY0tLScgRDDvFD+VVyDN2+AI9XN6NJCiPuxmFoEsK4ve5qPqjajscyGa/CS8fORwDQhamJzwqndl8HEyZORKVQYEtMAo+WTZ99jKOr88RO6LvoqoWX5uxXweTPC7bP+TfE9Gd9Qw3p2gDhBR3Umlu5fPY/qPAY2ZD9FP6AoL37Ylq8LtbUreG0U+/C2n0m3XVKvO4AScXv4tKoaEkYwD+H5RGtiKckMQZDRzXXbHiTF1ZXnNi5f5uAH7a8AFkzIHEoAHa/nyt3VRAAFg7PRpbuQ6lUMmnSpINOfXfzTcRTT7txGndNe53KTa2UPrKNGAnrtZJws5ZHxltwb9tG6anTKKmpYNC0U0JG7j7E9woMIcRSIcTuwzzOPrCfDOocvlPvIIRIAPKBLw9ovgPIBUYBkcCfvut8KeWzUsqRUsqRMTEx3zfsEEeBEeFGLoiP5LGqJv6vpBZp0hB5UR5KoeCqpnN4oNuKyiep7dhv2E7Pj6KtzsbuZU1MnzmThsREEtQKpN/PO/f+H37fSeZq27wPnpkMzYUw70WYfd/+Y/oIApNuZYs+A1vzBrJcKaSNyWNuQhxvpteQrtxHRcUoJtaMYERgEJ+Wf4oQgunT76G1cjxKbLQXrQVg3OmzmHpeP/qNOR+EiU3pcUTKRp5fvIN3Np9E6VSq1oK1AYZf2tu0qKWLapeHx3NTSXLZKCgoICsrC71+v5ttc8d2wmxf0y0imTf6OeyVVvwflZKkVrAkDP7isfKPufn4F31Ks9lAcV0lI86Yy/QrrjsRswzxE/legSGlnCmlHHSYx0KgqUcQfCMQmv/HpeYDH0kpe+8YUsoGGcQNvASMPrLphDjaPNA/mauTonmutpV3m9pRWbSYZ6QyumMgNxQsoLormhZlHZWVTwKQPy2Z3HHxbFlcSUpELlmZmVT1yya12U57TQWVO7ef4BkdgJTw8a8BAdetgkHnHdJlbdxIbKowBnQGtajR+am43U14Kx/B6QxjZcQ8DFLPX8t+RXFZIRVdFeBRE2jLJqJpJ3vj41BYYpg/azQanYrTfzuG0XPvQKHOpjQ+gotbPuO+zwqxu08C1ZS9DVY9AGpDMMlgD6varUSrVYy3GPnkk0+QUjJt2n5vJqttHwU7FiCEJDnjNjxWD00v7kYDVIyL5W+2bv521gBGFK6l7aWXaRnYH53JzKQLL0ehPMnTooQ4iCNVSX0CXN7z+nJg4f/oeyHfUkcdIGwEQfvH7iMcT4ijjFah4O/ZSWToNXzUFEzMZ56ZRtQVA0kmgbHb76Wp20RFxX/xeFpRKhVMvrA/ljgDy1/dy4Txk/FoNLgSE1H6A6x7790TPKMDKP4C6rcHDbvRhy9e9HBZMUgvf6zxolB5cOtr2bDxdHy+Buq75rAyOpUXz05AoVLzx/rLeX3j27z/wFYCrkoalRvwawJkji2lo2M1EEzDMmRmP9TG04n1RaN0t6HpbuKtE5200dEOz04N5tM69V/BeBRgXYeNJW1dTI40UV5WRm1tLVOnTiUhIQEAKQOsLrgVl9/He47+5Meezc4HtqDzBmjob+HazeWkRho4ZfdSGu66C+ewwdS4bORNmILygEC/EH2DIxUY/wJmCSFKgJk97xFCjBRCPP9NJyFEOpACrPrW+W8IIXYBu4Bo4O9HOJ4QxwAhBOfGRbCmw0aZI1idTp8bSfofxqM0qum/93p8ATcbNp5JR8dG1BolM68cgL3LQ8GnHQwcOJjq/v2J6/bQXLGP1S8/d4JnRNB19v2rICIdBh++SM+WLjsbHBZSnIUkeUagCeygcM08PB4327fN4cxpv2NBQhRPNLXx1ux4cp0ZsDIcR7cDX/fHeBRafP1TsGSp2bHzKoqK7yEQ8GCK1BGZGAaxMwGYrGnkudXllLfYDjuOY46tBd44P6iKumIRjAj+BlzTYeW8HaVEq9XMV/n46KOPiI6OZtiwYb2nLt1yJVrXXipEP56a/SYVT+8i0RfA3z+Cl1Ue1EoF716ST+cLL6CZPJFtEXpMUdGMnx+q0d0XOSKBIaVsk1LOkFJm96iu2nvat0gprzmgX6WUMklKGfjW+dOllPk9Kq5LpJQn6BsT4vu4IikarULwr/LGXhdZpVlLytVjCPdmkLrpTjrsnWzbfhGlZQ8Sm2Zi2iX9aSzvommzEl/Aj//Ca4jpcrDp84XUbVh/Yie05UWQAbhiMSgPrUWxrsPG3O0lKPwd3FMbjhRhqCeqsWrtVFbmMnrUGSQkJPBIbgpzYy084rLytlkQ2Z6L27YGn1KQe8YF6CNyKdh5BokJl1Jb+wrFxfcgpWTwtGS6ZSJ6n4asmg3gdnDpC5vodHiO7zpICR/9Cpp2w7wXICWoFe72+bmvrIEErZo30ixs/Oh99Ho9CxYsQK0OrteXhY+gsK5hpzeOa6csROxyYWp20Bah5TGDl6V7m/j15Az8jz6A12ZjV1IM3c3NnPbb36Mzhh3feYY4KoQivUP8IGI0am5Oi+PTlk5u2VdDty8YdKaON5L5p2kY3Nmot17DJruSqqqn6OhYT974RObfOYpIUzwar4WKmhK2jjoHpGTTQ/cjPcf55vgNxV/Cjjeh/2kQnnTI4TUdVq7eXYFedhPVfA/53fFos8KpTXMCkNvWyLSoViC4+3osL5XTwozQ4MHoaSaiYy0KCXMuOo9zzjmH9nYre/cOJjX1Gurq36K09J/kjUsgLT8Kf8R5uHxeflv3Pm2dVm57v+D4xqyULQs+Zv4NBgT9WFa3W5m2aR87rQ5uTY7i7ZdfRqFQcOGFFxIdHcw4W91dTW3109ikhl9P+QLPmha6PyqlwxfgvUgFH26v53fT+3FJ526aFy9mw6iBlBUWMGHBpSTnDTp+8wtxVAkJjBA/mBvT4vhdaizvNrYzf0dZME0GoNCqMI1MZrBtJG2VaVj9Sgp2/47u7gIiE4ycdeNQEhiK0hVOhLKdrvgcqqSHvZdcgru8/PhOomxFUBUVlQWz7j3ksCcQ4NaiGvQKH6r6v/G7nIuhzYsjZQ+NTc/S2RHPQGGFokW956gRnLa6A73Hj7buZTrC9FT30+CWHtLS0pgwYQIFBQVERf6KmJjZNDR+iFAGOP36weSNH4LaMJkWazu/7fiUpXvqWV3SeuzXIRCATc/Bu5eDJRVGXgXA5i47FxaUYVAq+Gx4NvGlhbjdbi677DKio6ORUvJRyUf85vPzSdf4yIi4HOszpXR/UYnDrGGDK8AbpU38dloWV1NN6f3/ZNugfjikn/Puupcx55x/7OcW4pgREhghfjBKIbgzK5FnB6azw+rgjfq23mOmaSkow9TcWP8bPmqIocXVyZYdV+P2tGK0aJn/x3FEWvOJUqejiAzHGRHDCp+VTddejaf6OBl8OyrhzflgToSL3gHLwdlii+wuTttaTKXTwzhlAQPtRk5fNwKXqZIy+ShOZxhC3ETkgGlQuBA2B810276qoqXYRnzVm9RbVBSmDGVAzO/Z+ulKgF6df1FREXFxZ+D1dtDRsRYhBINnpKLUjcSsGomns5GLmhby+zc2UlDbeezWobsBXjoVFt8aVEFd/llvnYv7yxuI06j5bHg2Q8J0bN26lZycHOLi4uj2dHPdkuu4e93dTLWYAQhblI3f6sGyoD/rrT4qFQEm94/hpoFh7P6/O1mdHodTr+X0391G+uBh/2tUIfoAIYER4kdzRqyFwSY9r9a34f/GnmFUE3V5PkoiuG/v7XzeHoPH28GuXb8lEPBgtGiZelEu6qZU1N5w3EkZtKTnsTHayJIrLqbjnePgPbX8PhAKuGxhUGgcQEBKri+spNHt48VB6cTuK+TB8t/TFPkGVePuweOz0t52BuecMw9m/CVYeW7xH9nyzDts+LgIdeu7VJpbUIZHUn/O+fzf0DAWdkazadVKoqKiSEhIYMmSJRTsDKDTJlO493bc7iZi08xMvbg/HtNkEh3xRDoamVv8Bve+uwHbsXC19TjgrQXQtAfOeRou+RAi0gBocntZ12ljXnwk4WoVGzZswG63M2LECACe3PEkmxo38X8j/8xEnxZtdwqWvHxibxnBu4srsLe5KNH4uX1WPxruuYcdSVGEx8Vz5SNPkzUi5DH/cyAkMEL8JK5PiWWf3cX1hVXY/UF7hibZRORZSSAtXFWm5612NV1dW9iydR5+v5PccQlc/NfxDIiehMGWAmYzrXG57IsJZ+fDD9D69DMEjpVdo3E37HoXxv7mEGGxy+rg7G2l7LG5uC87idEaL/OLp9E4YCFtSZ8QE30WmzadSb9+p6NQKEBvgXkvURcxn43bY1B3LMSqrKUhZiC/eui/fDp+MGdH6XkzXY39ayhdtp1LLrmEwYMHs3btFgoKJuL1Wtm85Vwamz4lb0IC6flRtCddhEU3DoOvm+FrX2LGQyvZXt1x+Pn8FKSET24Ilp4973kYemFvUkFvQDJ/ZxkSODMmnMWLF7NkyRJyc3PJzs7muYLneGPvG1wXeTljlutx6PYRHT2LyHk5FO5owVltpzBeyYMXxKH59WXUbt2MS61i/IJLQ5HcPyNCAiPET+KcuAhuy4hnYXMnT1Tvj9fUDckAAfmMJ2A38FF3FFbrHopL7u11KT3jt8MYmDkSlceMLjwSVWQSuzMSqf/P49TeeOOxGfCGp0BthAk3HdT8dbuV2VuKqXC6eTQ3hbNjLZSu3o6M2Y0t+RPi485Go7kWv19DUlLQQC6lZPWru1m453w0rjac/ipqtMlMuvZ36E1mVArB33MzUQjBKxkudEts2PY1cc4553DllVfidEaxb+9pKBTh7NlzM9u3X8TES1RMXpBDIGoyOuNwNCo746pXce2rW45eUN/Wl4JZaGfcHTT4H8Cilk6K7C7+lmhh+8cfsGnTJsaMGcO8efPo9nTz4u4XOds8h6m1LsrybkOh0JE6/CI6mxys+aSMdkWAq6/MJ/Dw/Xg6O6mdOgGVWkPm8FFHZ+whTgpCAiPET+b36fHMijLzcl0rzp76DgqDGnWyCav1FG6vMbGqy0mVyKS+/h127wnW0FBrlJx+/RAmTJ4ISg/WsFycCgVrh+dStn0Lrr17j+5A28qCu4uhF4J+/6/dTq+P24trSdNrWDsmlwUJUXR21OHvfoGGIU9hNg8nPv42Nm7ciBCiN1ht7b3vUrDVQWz7DircX+NTCoZmKDh7cELvtWM0aqZEmtmSFs/WsErc79XSsaSCtLQ0LrnkErq6Itm29VTSUv+M3VHG9h0XkTcxggnn98OvnYwxEEZq+zZyKlfzRUHNkc0/EICNz8BXd0PaRJh4y0GHq5xu7i6tI1kB9W+/Ql1dHbNnz2b27Nl4pIeLF13MhJbBXNgQS2P2i1jCRzF8yCK2furlzb9txNPtoT5NR3bpdmpK9rGqXyK1tZVMvfxaNHrDdwwqRF8kJDBCHBG/Tomh3evn/ab23raoS/JQhKmJcV/MDVYXj1Q3oo69mJaWJaxbP42Ozs0ATDllJIPyhuAzdOFMG4NVGc629HhW3Hs3rtaj4Cnk88DGZ+HFU0Glg8l/7D30UVMHUzcVUevy8HBuKuFqFV6nlZ2rr8AVux215gzaWi/miSeepaamhlmzZqHwB1j323+zqyYck6+Oh+IjMCkaiIo2cRlvwJ4PD/r436bG0umHf05KY4llK/Zltex7ciUWr4EFCxbQ0dHFBx80k5nxV/x+GzbbXnJGxZM6MAZf5OWYvFpGWLex7T9/Y0dZw7dn98PZ8UYwE2/SMDjnyV41FAS9wi4uKMfl9TFh03LS09K48cYbGTduHJ2eTm5ecTMD6qOZH9NFY+6TmI1DGTzsWVa80k7ByloqzPB6pJffzIpl7d//ypbMRLSRkcy/+x8MmXXa/xhUiL5ISGCEOCLGW8IYZjLw74pG6lxB+4MqXItpaioeXy4LnKcR4/dz165l6DP+gVoVVMN0d+9CoVAw74K5TJ8yi4DWjTJ8BkKXSKHfybO/vox1Tz6GDPzEynQeO7xyJnz+R4jODhq6TfEAtHp83LC3ilitio+G9WOcJYzS3W+wdvks/GGVNHeeSmnxEDZs2MHQoUP53e9+x/jx4/nyzx+x3T+CgMLNgxYLs8VeTFoVZ9/5AIrofvDhtbDlpf1rExHGf/PSqAyYWTVrAh+nrUbWumj+z3b0a6xcOvdCnE4nGzcGhYHVVohSreD03w4mOiUKT9wNJNkTiHS18OE/7qXb6f5pa7HnQ4jMhMs+6TVwf8PbDe2UOtxM2r2RQRYTF154IUajkR3NO7ji8ytQl9k5N86BNW4b6ek3Em14hPcf2E1dUQdL9B4Wadz8N66OvXffwJ7YcJJzB3DB3+4nZeDgnzbWECc1IYER4ogQQnB//2S6fX7GbdjLvysakFISNi4BdYoJa9v5PFd1JpFeL79b+wCBuCvx+53s2n0jsqcU6vjJY0hISMBqKcUWOYOujFOJCMD6VUv46v5DYyV+EGsegZoNwWpxVyyCpOG9h16rb8Uv4ZHcVEaEG6nY/hJVzXcjfWqKK06haHckzc3NzJ07l7POOgujMYzN7xVQaY9D2PbyYISKGyZFYm4pZvDMU4lISoGrvgqmBP/sZlh2L/iCN/dz4iK4Mimar7o17Jp8Ie/MWs8b0Yuw7m1G9UEzIzIHs2tXDX6/gfa2YGVCpVLBuX8YTvaoONqSL8RCKuG2ap67fAErl6/74WvQsBPevhjKlsOAcw7aWQDstjr4c0kd6S4bOY4uLr74YjQaDS/tfonfL76Jm3fP55LobhzR20iN+hXO2vNZ/GQJjc12vjB4GDEthaVTDbS8/zy1Rg1Dx05i3l//hcEc/tP+ZiFOekICI8QRM9hk4OvRuZweE85DlU38vqgGvxDEXjcY47gEtO4zeHrfBUzuTua2Df8lJu1mXK4aiovvJRDwolKpuOyyy4iNiSMQvg+NM5biAdeQbnWze8dmlj3zH3w/xntqw9Pw9b+DkcuD5x90o3yzvo37KxoZYtIzwKjDuquB6oYnEV1pbCw6lea6OKZOncrNN9/MkCFDAPj6jX1sWtZKRNtuXo+y8N9JOryfPoHBHM7QU04PXtgYBQvegPzzYfWD8OnN4A1Ghv89O4kbU2NZ2NzF3ojL6Dd/Ab/PepBaGhhWGMN09VCaGlNpbfuCVavOorNrKxq9iplXDmDQlCScEfPQGk5F43NT8N+/s+31178/GrxmEzw3HSpXw+TbDlLHAfh8Pv6+aScBn5cpW79m+rRptPvb+dWSX/Hwlof5S/NvSTA344gqpF/G/9Gw9wxWvVmENsnA41o7M+ZkctfpuRS//Axl8ZFkDhvJjFv+hFCEbik/Z0SfKJ35LUaOHCm3bNlyoocR4ltIKfl3ZSMPVzYx1GTgmYFppOo02L6upXtpOdKrYKuxgKcyP+CGjHD0rgLCwgaQnvZr4uJOx+128/yzL9La2orWnsh2m+CcsleojzQRrjMwfM7Z5J99Hmqd7rsHYW2E/4yE+EGw4E0wRALQ4vHyZn07D1Y2MibcyKuDM6kp2kHLjvtxx29hY8NIPCV5LFiwgNzcXAD8vgDrPypl57Jakuq+ZntmOCOn5VL81hNY4hI47857sMQnHDqGJXfD2scgJg/OeATSxuGXkqdrWniqupkAkgdTnbyz+7+oy31c37YAr9tPefZCwuO3oNV6GTb0JSIjxwPQWmvlvX9uwWSuoaPoLTxqJePGTWX8zbcefg1aiuG1ucFqedet7F2DA/n7p1/wjC6KYX4Xzw3LodRXyp1r7sTr8/JP9e1k7DBSP+sRnLKN8kX/wmX3EzbIwqONzWQlmXnqzBRWvvAk1YW7iDGamffIkxjCLT/m3yXECUAIsVVKOfInnx8SGCGONu82tnN7cS1DTQbeG5qFUggCbj/2xWvo3BigQ9vNO5alxOV3MERfi89dw5DBzxEdPZ3Ozk4++3QRpaUlKAJasCURU7Uehb8Mm06DGsHMOXMZcPlVh37wyvuDv+5lAK5dDglD2NRp44W6Vha3dOGVkllRZv6WEca+T17GaHkPn74dheZMaiuH09XZzQ033ABA7b52lr+2D2ubi7imTbSFdzL28hmsfeMlwiIiuei+h1EdUJ70IKSEkq/g4+vB0Rr8dT/5j6DSUupwMWtzERMjTLw0KINl1V/xl+X/x4Vdp3NmxxTeVy9n4PDPMBo15PS/jdiY2ahURla9VcSe1fUs0jQzt/wlnCo4I7U/sRddjGHkyOAv+28+951Lg8LiysXButzf4uW9ZdzeaCVW+vl03CA2Vi/k3g33kqfN4cGuP0GVlZrxD+My7KN553m4nfPYYvDzWWM7/eNM/HdWHEv//Wc8Tgc59W1MffZF9AMGHM1/oRDHiJDACHFS8mZDG7/fV8OvU2L4a7+eBH9S4n7uFjorh+INZOEVPj6NXEbWqK8wYCcl5QoyM25BoVBRVlzBhx98hN1lxdI+hEafhkFiJ7amNUi/l7PGTCP28stRJyYGvaHevghKlwR19dPuxBuVw71l9Txb24JFpWR+fCSnRkgKK55AVfc1qcZ2ZEBPv/73IBSDefnllxk1ahSnnXYaLbU23vvHRjT2FuKr36EyXk9A7cHrdhGVnMpZf7iLyMRDkxYegscRNLpvfz3ozjvjLzDySp6paeYvpfWMDTdyd79EFK4SblpxE6ntMVzVdD4lYZtJzFuCXm8DqSU+fg5RlvP57CE3Do+fzYFKhrZ9iMHrJbm1i3RdGP1uvhh99xLY9xlE9Qsa+cOTDxlSVVMTZ20twa5U8enwGN4peY0PSj5gZOxIHuj6I66CZqqm3I9bXUzXvuuo057CQ8X1xJq1XDEhnQu797LsyUeoNuuZhp7s391C2MQJR/efJ8QxIyQwQpy03F5cy8t1rfwhPY758ZGk6bU9tRfOw9MmaEt/DH+BlaqwYipGPE+CtpnwmLMZmvc3VCoTdrudZ555hu7ubtTuOMI7cgiIGrzt72NyuknssjPorLmkDepCrP8PTLoVpt5BnTfAAxWNvNPYztVJ0VwTr+TNwhcpqPmAayK7UPkMmNpHk3f6n6motrN48WK0Wi3XXnstNge88veNmLu7UTc9Q0eYAo3BQP9xkxgwaRpJ/Qf8OD29lFC+Ar5+CKrXB4sTDb2I9zs83F5ci90f4D95qUwIc/Ne8Xu8tOslRnuHMLV7PG5Ziip+J/ExNQiVlwH93mXNm36aK7vxeCtRKTbj6a4BKYlz2hmV3Uz2mVegGP8b0JoOGoY3IHlk516ebrHiUGsZ0LGGFuszKISCC/tfyBU1Z+DeUUND3krsCe/TvvtamjPO5sF15Zw9JJEH5g3B+flilj38LypiLeSPmcApv7/jKP/HhDjWhARGiJMWlz/Ab/dWsailC4Bsg5bLk6K52l2IeO0sZNYs7Fn/pPmrOvAEWDz8LvIimwlIgS9sJJOHPYvwqVi5ciWbNm3CrzCgskYR1uEEzzZwN6Py++nX2c7ATAsttz3Dvd1eNnXZAbggWtBa8wD7Wgq4SpVMbmwlalckSWX30DRMS1l1BWVlZURERHDu2fMoWN5ByaZ6hLuM8JbPaTMGGHbqmUy++MrvVj/94MXogrcugqo1kDoerlhEd0By+a5ytnc7+Fu/JC6Ij2RXy1be2vcWK6pXoPIpmG89D7fVyuhRC1EoBMnKGxHG2ax8ew0+ZwIBfxcKzzZ8jj34FD76p2Yy47e/R5+eTkBKNnfZWdnaxetV9bQo1MR2NyGsr5Nn8TE7/RRmJs1A8UUxDd436EpaDULisuXx4L5bqGh3MXtgHA9Mi6f6qSfYtW0jDWYDg2ecyoyrfxMqr9oHOaECQwhxPvBXIA8YLaU87F1cCHEq8BigBJ6XUn5TmS8DeBuIArYCl0opv9cdJiQw+hYVDjdL27r5rKWTjV12sg1axrnKGVr0NkO695JlyqKz+3f4HFA4cCOVqo/IMtdT7Q8nI+3XDE+9gLK95ezevZuysjJAgdptQmsLx+9cw8acgewcMBq70YRJ+rkpK5kk+172bX+I/noH4eZaUPgwdg8mIXALH1RsodvaTVRUFP3S+2PyZ7D9qxL8zlJ8zjUI6UDlDzDotDOYcuk1Ry4svkFKWP9f+OrPMPZ6mPlX6n2CC3aWUeJwo1cI5sVHckNqLNLTwHvF7/HantcYbxvLWEUElsQVmMxt4FeSUGdG7c/l5eqzcLdFkO4VBBzL6BaltETG05yaw96cITQazQgpie1uJ6l5Nf37dbMg9wIGmMJp3PcVdW2v4dcEgy5t9aewyD6alaXhzPA3MEdU4GyspN7jwK9QoBSCkbPPYPxl14SERR/lRAuMPCAAPAPcejiBIYRQAsXALKAW2AxcKKUsFEK8C3wopXxbCPE0sFNK+dT3fW5IYPRNpJS819TBuw3t7LQ6sPakE9EGPGTZG0i3hZNu1ZNpCxBtXoUy4yUUCh8uj442mUl8+lw6G71srnGxRZNKiyGC1rCgz392WxPjWvcxWhQSlbqZgK4bAKXHhLlrDAmpc4kdPYuPP1rM7t3byAgfRFdpM35rLQFfPdLXAgLMDjcDhJb8P/wR85Qpx2IRYPEfYfNzYIiClDHIhGGsTZjKR24z77W78SP5VXIsp8WE0921nZtW/AaDQs0gZyQjPLFERDUTE1dJO1HU+rOo8w9hnzebckUqnYZgnWwRCJDc1khOew05XWX0bykiIzMJfYKRTv1avJomAHTt/WmtG82OJgu+3aUM6Kwg3ttKYXwELo0KtYT0yFgyTzmNrFmz0ZvMR39NQhw3TgqVlBBiJd8tMMYBf5VSzu55/43i819ACxAvpfR9u9//IiQw+j4BKalwutlpdVLQ1kJRWxPFHkGdYn/pTq3fT4TfiVR6QeGmGxNOYQQgQraRHKgnU5YyVfElsaKl97yO9gTa25NwdFvobrcgUYBQIBVKUCpQdbejrwsWbhJSYERDTFIyg8aPJ/OUU1GFH4fAs/KVsOMtqN8GrSVA8HvYoInmvuwbeD96Wm9XZcCHOuBASA8eoUIKPQGF5qD4kgjZRg5FpAfKSfbVkSYrsKg6UCq/lbhQCtStmfiqsuiq11BfW4X0u5BC4FMKAj32mbAwM3N+czPJw0eGYit+RhypwFAdzcF8B0nAgdnTaoExBNVQnVJK3wHt3+l6IoS4DrgOIDU19diMNMRxQyEEWQYdWQYd58ZFADkAWH1+Stoa2ddcS5HdSZvbQ8DlxeXwIUUX/f2NRItuMrxlgA2fSuLQZtOtG4+UyTRURWFv1ROwdSFdbSgDdkQggAj4EQEPGr+fSHeAiLQhZOTn0m/aVAzJKf9rqMeGzKnBB4CjHWo2gq2JBFsz/7XV8ueOl9hpyKBYG49VE4ZVE4HNlI1CBAj4bMiAE1WgG629AWVVLRZ3LdG6FoxqF3qVwBjIQusOx+uKwOky4bYrcXcLOtu6EHYbukAHatqJDzeh1MeiiY3FkJxCeGIiEfGJJOUO/N/xLiF+kXyvwBBCLAXiD3PoLinlwqM/pMMjpXwWeBaCO4zj9bkhji8mlZLhcUkMj/sBbqs/FwyRh6Qbj+95fO92G2DiMRhTiBCH4XsFhpRy5hF+Rh1w4E+45J62NsAihFD17DK+aQ8RIkSIECchx0M5uRnIFkJkCCE0wALgExk0nqwA5vX0uxw4bjuWECFChAjx4zgigSGEmCuEqAXGAYuEEF/2tCcKIRYD9OwebgC+BPYC70op9/Rc4k/A74UQpQRtGi8cyXhChAgRIsSxIxS4FyJEiBC/EI7USyrkLxciRIgQIX4QIYERIkSIECF+ECGBESJEiBAhfhAhgREiRIgQIX4QfdLoLYSwAkUnehwnCdFA64kexElCaC32E1qL/YTWYj/9pZSm7+92eI5HapBjQdGRWPp/TgghtoTWIkhoLfYTWov9hNZiP0KII3IvDamkQoQIESLEDyIkMEKECBEixA+irwqMZ0/0AE4iQmuxn9Ba7Ce0FvsJrcV+jmgt+qTRO0SIECFCHH/66g4jRIgQIUIcZ0ICI0SIECFC/CD6lMAQQpwqhCgSQpQKIW4/0eM51gghXhRCNAshdh/QFimEWCKEKOl5juhpF0KIx3vWpkAIMfzEjfzoI4RIEUKsEEIUCiH2CCFu6mn/xa2HEEInhNgkhNjZsxZ/62nPEEJs7JnzOz3lBBBCaHvel/YcTz+hEzgGCCGUQojtQojPet7/ItdCCFEphNglhNjxjQvt0fyO9BmBIYRQAk8ApwEDgAuFEANO7KiOOS8Dp36r7XZgmZQyG1jW8x6C65Ld87gOeOo4jfF44QP+IKUcAIwFftvz9/8lrocbmC6lHAIMBU4VQowF7gcekVL2AzqAq3v6Xw109LQ/0tPv58ZNBMsnfMMveS2mSSmHHhB7cvS+I1LKPvEgWHPjywPe3wHccaLHdRzmnQ7sPuB9EZDQ8zqBYBAjwDPAhYfr93N8ECy2NeuXvh6AAdgGjCEYzazqae/9vhCsRTOu57Wqp5840WM/imuQ3HMjnA58Bohf8FpUAtHfajtq35E+s8MAkoCaA97X9rT90oiTUjb0vG4E4npe/2LWp0eNMAzYyC90PXpUMDuAZmAJUAZ0ymDBMjh4vr1r0XO8i2DBsp8LjwK3AYGe91H8ctdCAl8JIbYKIa7raTtq35G+mhokBCCllEKIX5RftBAiDPgAuFlK2S2E6D32S1oPKaUfGCqEsAAfAbkndkQnBiHEGUCzlHKrEGLqCR7OycBEKWWdECIWWCKE2HfgwSP9jvSlHUYdkHLA++Setl8aTUKIBICe5+ae9p/9+ggh1ASFxRtSyg97mn+x6wEgpewEVhBUu1iEEN/8CDxwvr1r0XM8HGg7viM9ZkwAzhJCVAJvE1RLPcYvcy2QUtb1PDcT/CExmqP4HelLAmMzkN3j/aABFgCfnOAxnQg+AS7veX05QV3+N+2X9Xg+jAW6DtiG9nlEcCvxArBXSvnwAYd+ceshhIjp2VkghNATtOXsJSg45vV0+/ZafLNG84Dlskdp3deRUt4hpUyWUqYTvCcsl1JezC9wLYQQRiGE6ZvXwCnAbo7md+REG2l+pEFnDlBMUF9714kez3GY71tAA+AlqF+8mqC+dRlQAiwFInv6CoJeZGXALmDkiR7/UV6LiQT1swXAjp7HnF/iegCDge09a7EbuLunPRPYBJQC7wHannZdz/vSnuOZJ3oOx2hdpgKf/VLXomfOO3see765Rx7N70goNUiIECFChPhB9CWVVIgQIUKEOIGEBEaIECFChPhBhARGiBAhQoT4QYQERogQIUKE+EGEBEaIECFChPhBhARGiBAhQoT4QYQERogQIUKE+EH8P8yF+Uefyf3kAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "n_samples = 10\n",
    "length = 500\n",
    "_a = []\n",
    "for i in range(n_samples):\n",
    "    a = np.arange(-4000, 4000, 10)\n",
    "    mask = np.random.rand(len(a)) > .5\n",
    "    a = a[mask]\n",
    "    a = np.concatenate([a, np.array([np.nan] * (length - len(a)))])\n",
    "    _a.append(a.reshape(-1,1))\n",
    "a = np.concatenate(_a, -1).transpose(1,0)\n",
    "sin, cos = encode_positions(a, linear=False)\n",
    "test_eq(a.shape, (n_samples, length))\n",
    "test_eq(sin.shape, (n_samples, length))\n",
    "test_eq(cos.shape, (n_samples, length))\n",
    "plt.plot(sin.T)\n",
    "plt.plot(cos.T)\n",
    "plt.xlim(0, 500)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "n_samples = 10\n",
    "length = 500\n",
    "_a = []\n",
    "for i in range(n_samples):\n",
    "    a = np.arange(-4000, 4000, 10)\n",
    "    mask = np.random.rand(len(a)) > .5\n",
    "    a = a[mask]\n",
    "    a = np.concatenate([a, np.array([np.nan] * (length - len(a)))])\n",
    "    _a.append(a.reshape(-1,1))\n",
    "a = np.concatenate(_a, -1).transpose(1,0)\n",
    "lin = encode_positions(a, linear=True)\n",
    "test_eq(a.shape, (n_samples, length))\n",
    "test_eq(lin.shape, (n_samples, length))\n",
    "plt.plot(lin.T)\n",
    "plt.xlim(0, 500)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def sort_generator(generator, bs):\n",
    "    g = list(generator)\n",
    "    for i in range(len(g)//bs + 1): g[bs*i:bs*(i+1)] = np.sort(g[bs*i:bs*(i+1)])\n",
    "    return (i for i in g)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "generator = (i for i in np.random.permutation(np.arange(1000000)).tolist())\n",
    "l = list(sort_generator(generator, 512))\n",
    "test_eq(l[:512], sorted(l[:512]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_subset_dict(d, keys):\n",
    "    return dict((k,d[k]) for k in listify(keys) if k in d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "keys = string.ascii_lowercase\n",
    "values = np.arange(len(keys))\n",
    "d = {k:v for k,v in zip(keys,values)}\n",
    "test_eq(get_subset_dict(d, ['a', 'k', 'j', 'e']), {'a': 0, 'k': 10, 'j': 9, 'e': 4})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def create_dir(directory, verbose=True): \n",
    "    if not is_listy(directory): directory = [directory]\n",
    "    for d in directory:\n",
    "        d = Path(d)\n",
    "        if d.exists():\n",
    "            if verbose: print(f\"{d} directory already exists.\")\n",
    "        else: \n",
    "            d.mkdir(parents=True, exist_ok=True)\n",
    "            assert d.exists(),  f\"a problem has occurred while creating {d}\"\n",
    "            if verbose: print(f\"{d} directory created.\")\n",
    "\n",
    "\n",
    "def remove_dir(directory, verbose=True):\n",
    "    if not is_listy(directory): directory = [directory]\n",
    "    for d in directory:\n",
    "        d = Path(d)\n",
    "        if d.is_file(): d = d.parent\n",
    "        if not d.exists():\n",
    "            if verbose: print(f\"{d} directory doesn't exist.\")\n",
    "        else:\n",
    "            shutil.rmtree(d)\n",
    "            assert not d.exists(), f\"a problem has occurred while deleting {d}\"\n",
    "            if verbose: print(f\"{d} directory removed.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "wandb3/wandb2/wandb directory created.\n",
      "wandb3/wandb2/wandb directory removed.\n",
      "wandb3/wandb2 directory removed.\n",
      "wandb directory doesn't exist.\n",
      "wandb3 directory removed.\n"
     ]
    }
   ],
   "source": [
    "path = \"wandb3/wandb2/wandb\"\n",
    "create_dir(path)\n",
    "assert Path(path).exists()\n",
    "\n",
    "paths = [\"wandb3/wandb2/wandb\", \"wandb3/wandb2\", \"wandb\"]\n",
    "remove_dir(paths)\n",
    "for p in paths: \n",
    "    assert not Path(p).exists()\n",
    "\n",
    "path = \"wandb3\"\n",
    "assert Path(path).exists()\n",
    "remove_dir(path)\n",
    "assert not Path(path).exists()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "test directory created.\n"
     ]
    }
   ],
   "source": [
    "create_dir('./test')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing ./test/mod_dev.py\n"
     ]
    }
   ],
   "source": [
    "%%file ./test/mod_dev.py\n",
    "a = 5\n",
    "def fn(b): return a + b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "test directory removed.\n"
     ]
    }
   ],
   "source": [
    "fname = \"./test/mod_dev.py\"\n",
    "while True: \n",
    "    if fname[0] in \"/ .\": fname = fname.split(fname[0], 1)[1]\n",
    "    else: break\n",
    "if '/' in fname and fname.rsplit('/', 1)[0] not in sys.path: sys.path.append(fname.rsplit('/', 1)[0])\n",
    "mod = import_file_as_module(fname)\n",
    "test_eq(mod.fn(3), 8)\n",
    "sys.path = sys.path[:-1]\n",
    "remove_dir('./test/')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class named_partial(object):\n",
    "    \"\"\"Create a partial function with a __name__\"\"\"\n",
    "    \n",
    "    def __init__(self, name, func, *args, **kwargs):\n",
    "        self._func = partial(func, *args, **kwargs)\n",
    "        self.__name__ = name\n",
    "    def __call__(self, *args, **kwargs):\n",
    "        return self._func(*args, **kwargs)\n",
    "    def __repr__(self):\n",
    "        return self.__name__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add_1(x, add=1): return x+add\n",
    "test_eq(add_1(1), 2)\n",
    "add_2 = partial(add_1, add=2)\n",
    "test_eq(add_2(2), 4)\n",
    "test_ne(str(add_2), \"add_2\")\n",
    "add_2 = named_partial('add_2', add_1, add=2)\n",
    "test_eq(add_2(2), 4)\n",
    "test_eq(str(add_2), \"add_2\")\n",
    "\n",
    "class _A():\n",
    "    def __init__(self, add=1): self.add = add\n",
    "    def __call__(self, x): return x + self.add\n",
    "    \n",
    "test_eq(_A()(1), 2)\n",
    "_A2 = partial(_A, add=2)\n",
    "test_eq(_A2()(1), 3)\n",
    "test_ne(str(_A2), '_A2')\n",
    "_A2 = named_partial('_A2', _A, add=2)\n",
    "test_eq(_A2()(1), 3)\n",
    "test_eq(str(_A2), '_A2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# export\n",
    "def yaml2dict(fname):\n",
    "    with maybe_open(fname, 'r') as f:\n",
    "        dictionary = yaml.safe_load(f)\n",
    "    return AttrDict(dictionary)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing sweep_config.yaml\n"
     ]
    }
   ],
   "source": [
    "%%file sweep_config.yaml\n",
    "\n",
    "program: wandb_scripts/train_script.py          # (required) Path to training script.\n",
    "method: bayes                                   # (required) Specify the search strategy: grid, random or bayes\n",
    "parameters:                                     # (required) Specify parameters bounds to search.\n",
    "   bs:\n",
    "      values: [32, 64, 128]\n",
    "   depth:\n",
    "      values: [3, 6, 9, 12]\n",
    "   fc_dropout:\n",
    "      distribution: uniform\n",
    "      min: 0.\n",
    "      max: 0.5\n",
    "   lr_max:\n",
    "      values: [0.001, 0.003, 0.01, 0.03, 0.1]\n",
    "   n_epoch:\n",
    "      values: [10, 15, 20]\n",
    "   nb_filters:\n",
    "      values: [32, 64, 128]\n",
    "name: LSST_sweep_01\n",
    "metric: \n",
    "   name: accuracy                              # This must match one of the metrics in the training script\n",
    "   goal: maximize\n",
    "early_terminate: \n",
    "   type: hyperband\n",
    "   min_iter: 3\n",
    "project: LSST_wandb_hpo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "- program: wandb_scripts/train_script.py\n",
      "- method: bayes\n",
      "- parameters: \n",
      "  - bs: \n",
      "    - values: \n",
      "      - 32\n",
      "      - 64\n",
      "      - 128\n",
      "  - depth: \n",
      "    - values: \n",
      "      - 3\n",
      "      - 6\n",
      "      - 9\n",
      "      - 12\n",
      "  - fc_dropout: \n",
      "    - distribution: uniform\n",
      "    - min: 0.0\n",
      "    - max: 0.5\n",
      "  - lr_max: \n",
      "    - values: \n",
      "      - 0.001\n",
      "      - 0.003\n",
      "      - 0.01\n",
      "      - 0.03\n",
      "      - 0.1\n",
      "  - n_epoch: \n",
      "    - values: \n",
      "      - 10\n",
      "      - 15\n",
      "      - 20\n",
      "  - nb_filters: \n",
      "    - values: \n",
      "      - 32\n",
      "      - 64\n",
      "      - 128\n",
      "- name: LSST_sweep_01\n",
      "- metric: \n",
      "  - name: accuracy\n",
      "  - goal: maximize\n",
      "- early_terminate: \n",
      "  - type: hyperband\n",
      "  - min_iter: 3\n",
      "- project: LSST_wandb_hpo\n"
     ]
    }
   ],
   "source": [
    "fname = \"sweep_config.yaml\"\n",
    "sweep_config = yaml2dict(fname)\n",
    "print(sweep_config)\n",
    "test_eq(sweep_config.method, 'bayes')\n",
    "test_eq(sweep_config['metric'], {'name': 'accuracy', 'goal': 'maximize'})\n",
    "os.remove(fname)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def str2list(o):\n",
    "    if o is None: return []\n",
    "    elif o is not None and not isinstance(o, (list, L)):\n",
    "        if isinstance(o, pd.core.indexes.base.Index): o = o.tolist()\n",
    "        else: o = [o]\n",
    "    return o\n",
    "\n",
    "def str2index(o):\n",
    "    if o is None: return o\n",
    "    o = str2list(o)\n",
    "    if len(o) == 1: return o[0]\n",
    "    return o\n",
    "\n",
    "def get_cont_cols(df):\n",
    "    return df._get_numeric_data().columns.tolist()\n",
    "\n",
    "def get_cat_cols(df):\n",
    "    cols = df.columns.tolist()\n",
    "    cont_cols = df._get_numeric_data().columns.tolist()\n",
    "    return [col for col in cols if col not in cont_cols]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "alphabet = L(list(string.ascii_lowercase))\n",
    "ALPHABET = L(list(string.ascii_uppercase))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_mapping(arr, dim=1, return_counts=False):\n",
    "    maps = [L(np.unique(np.take(arr, i, dim)).tolist()) for i in range(arr.shape[dim])]\n",
    "    if return_counts:\n",
    "        counts = [len(m) for m in maps]\n",
    "        return maps, counts\n",
    "    return maps\n",
    "\n",
    "def map_array(arr, dim=1):\n",
    "    out = stack([np.unique(np.take(arr, i, dim), return_inverse=True)[1] for i in range(arr.shape[dim])])\n",
    "    if dim == 1: out = out.T\n",
    "    return out"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([['h', 'a', 'g', 'H', 'G', 'J'],\n",
       "        ['f', 'o', 'c', 'J', 'J', 'J'],\n",
       "        ['e', 'j', 'e', 'I', 'J', 'H'],\n",
       "        ['m', 'i', 'o', 'G', 'G', 'G'],\n",
       "        ['c', 'j', 'h', 'H', 'H', 'G'],\n",
       "        ['i', 'd', 'c', 'H', 'I', 'I'],\n",
       "        ['f', 'f', 'l', 'G', 'I', 'I'],\n",
       "        ['l', 'n', 'i', 'I', 'G', 'G'],\n",
       "        ['e', 'i', 'o', 'H', 'G', 'G'],\n",
       "        ['j', 'd', 'f', 'I', 'I', 'J']], dtype='<U1'),\n",
       " [(#8) ['c','e','f','h','i','j','l','m'],\n",
       "  (#7) ['a','d','f','i','j','n','o'],\n",
       "  (#8) ['c','e','f','g','h','i','l','o'],\n",
       "  (#4) ['G','H','I','J'],\n",
       "  (#4) ['G','H','I','J'],\n",
       "  (#4) ['G','H','I','J']],\n",
       " [8, 7, 8, 4, 4, 4])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.asarray(alphabet[np.random.randint(0,15,30)]).reshape(10,3)\n",
    "b = np.asarray(ALPHABET[np.random.randint(6,10,30)]).reshape(10,3)\n",
    "x = concat(a,b,dim=1)\n",
    "maps, counts = get_mapping(x, dim=1, return_counts=True)\n",
    "x, maps, counts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([['i', 'j', 'e'],\n",
       "        ['i', 'o', 'h'],\n",
       "        ['b', 'h', 'm'],\n",
       "        ['d', 'i', 'm'],\n",
       "        ['g', 'h', 'c'],\n",
       "        ['m', 'n', 'k'],\n",
       "        ['f', 'l', 'f'],\n",
       "        ['m', 'k', 'j'],\n",
       "        ['g', 'g', 'g'],\n",
       "        ['k', 'e', 'j']], dtype='<U1'),\n",
       " array([[4, 4, 1],\n",
       "        [4, 8, 4],\n",
       "        [0, 2, 7],\n",
       "        [1, 3, 7],\n",
       "        [3, 2, 0],\n",
       "        [6, 7, 6],\n",
       "        [2, 6, 2],\n",
       "        [6, 5, 5],\n",
       "        [3, 1, 3],\n",
       "        [5, 0, 5]]),\n",
       " array([[4, 4, 1],\n",
       "        [4, 8, 4],\n",
       "        [0, 2, 7],\n",
       "        [1, 3, 7],\n",
       "        [3, 2, 0],\n",
       "        [6, 7, 6],\n",
       "        [2, 6, 2],\n",
       "        [6, 5, 5],\n",
       "        [3, 1, 3],\n",
       "        [5, 0, 5]]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.asarray(alphabet[np.random.randint(0,15,30)]).reshape(10,3)\n",
    "x, map_array(x), map_array(x, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# export\n",
    "def log_tfm(o, inplace=False):\n",
    "    \"Log transforms an array-like object with positive and/or negative values\"\n",
    "    if isinstance(o, torch.Tensor):\n",
    "        pos_o = torch.log1p(o[o > 0])\n",
    "        neg_o = -torch.log1p(torch.abs(o[o < 0]))\n",
    "    else: \n",
    "        pos_o = np.log1p(o[o > 0])\n",
    "        neg_o = -np.log1p(np.abs(o[o < 0]))\n",
    "    if inplace:\n",
    "        o[o > 0] = pos_o\n",
    "        o[o < 0] = neg_o\n",
    "        return o\n",
    "    else:\n",
    "        if hasattr(o, \"clone\"): output = o.clone()\n",
    "        elif hasattr(o, \"copy\"): output = o.copy()\n",
    "        output[output > 0] = pos_o\n",
    "        output[output < 0] = neg_o\n",
    "        return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "arr = np.asarray([-1000, -100, -10, -1, 0, 1, 10, 100, 1000]).astype(float)\n",
    "plt.plot(arr, log_tfm(arr, False))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "t = tensor([-1000, -100, -10, -1, 0, 1, 10, 100, 1000]).float()\n",
    "plt.plot(t, log_tfm(t, False))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def to_sincos_time(arr, max_value):\n",
    "    sin = np.sin(arr / max_value * 2 * np.pi)\n",
    "    cos = np.cos(arr / max_value * 2 * np.pi)\n",
    "    return sin, cos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYIAAAD4CAYAAADhNOGaAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAtrUlEQVR4nO3df3Rc5Xng8e+jQQ4D3VpW7FKQbfBSDinExlpUoOucntYQfgVslRLxI3ShSfBmEzYFUhez4YDjNYtZn8QkLd3WJRRaKFgQIwyBdYlNtiduoMiVLWOoi0Ma7IEEJ0beDVZjIT37x71XHo3uvTOjuXPn3rnP5xwdae7ckV79us993/d5n1dUFWOMMdnV0ugGGGOMaSwLBMYYk3EWCIwxJuMsEBhjTMZZIDDGmIw7ptENmIqZM2fqKaec0uhmGGNMqmzfvv2nqjqr9HgqA8Epp5xCf39/o5thjDGpIiI/8jtuQ0PGGJNxFgiMMSbjLBAYY0zGWSAwxpiMs0BgjDEZF0nWkIg8CFwGvKuqH/V5XoCvA5cCh4EbVPWf3OeuB+5wT12tqg9H0aZJnr0Vtj8EOgqSg7NvgMu+VpcvlWZ9AwXWbt7D20PDnNSW53c+MosX//nA+OPlF51Od2dHo5tpTLYM9sKWVXBoP0yfDeffCQt6Ivv0EkX1URH5LeDnwF8HBIJLgf+KEwjOBb6uqueKSDvQD3QBCmwHzlbV98K+XldXl1aVPvrsrdD/Tf/nps+J/IeaBt4FvzA0PH5MgJYWYXQs/G9ixnGt3HX5mRYQjInDYC8880UYOfq/SmseLv9G1dctEdmuql2lxyPpEajq34vIKSGnLMUJEgq8JCJtInIi8NvAC6p60G3kC8DFwGNRtGvc9oeCnzu0DzYug403ZiIo9A0UWLlpN0PDI5OeUygbBADeOzzC7Rt3AVgwMCZqpXf/R96fGATAebxlVWTXqrgWlHUA+4oe73ePBR2fRESWAcsA5s6dW91X19FyJzjvDu1zIi80XTAICwBTMTwyytrNeywQGFOr4gt/fgYc+TmMHnGeO7Qv+HWH9kfWhNSsLFbV9cB6cIaGqnqx5CoIBq6II20jFQ//COPhLjJvDw2XP8kYE2ywF57+wtEL//DByl87fXZkzYgrEBSAOUWPZ7vHCjjDQ8XHvxv5Vz/7huA5Aj+H9ju/oOdvO/qLybfDJfemIkD43f3XYx+6k9rydfisxmTI87cdDQLVaM07w9gRiSsQbAJuEpHHcSaLD6nqOyKyGfgfIjLDPe9C4PbIv7qXHeRlDZWTnwF9n4exomGU4YNO5IZEB4O+gQK3b9zF8EiFPSAfx0/LcfjI6HjW0LM735k0pJRvzbH8otND21EcjGyC2RgflfYA8u0w7fjEZw09hnNnPxP4CXAX0Aqgqn/upo/+Kc5E8GHgD1S1333tp4H/5n6qu1X1r8p9vaqzhkqNj8ntg9JBk9Y8HJMP/wUluHewaM3WCZlA1ciJcM25c1jdPX/Sc6VppWFppH0DBZY/sZORkonn1pyw9sqzLBiYbPJLAd14Y/nXTTFDyE9Q1lAkgSBuNQeCYr6/nGWUHUzJTYOl9ycmGPilg5ZTr7v0sGCUE+GrPRYMTMY8eyv0P8ikm05aYOT9yedLC6hGfvdf1/TRVFvQM/mHPN5bCDF6JDGTypUOB3l9n446LwwLm0QeVbXUU5Mtg72TgwA4iSn5dudaUjwM3dIK3X8W67XFSkz4Of9O55dRToTpW7VYu3lP2SAw47hW1l21kH9d8wm2rVhc14twuUlkL/XUmEzYsorAEYbh95yL/vQ5gDjvYw4CYD0Cf94voThryE+E6Vu1CLsDr/fdv5/lF53uO0dQrDA0zKI1W61khWlOxUPOYcPM02f7j0rEzAJBEO+XM9g7OYMInDmCCNO3anFSW953TL6jLc+2FYtjb493YS+3gK0wNGzDRKb5+JWE8CWJuYbY0FA5C3qcrlq+/eixfHuiJoqXX3Q6+dbchGPl0jvrrbuzgx13Xch9Vy2c1LZiNkxkmspgLzz1ucqCQNenE3MNsayhJlFNemfcKsloEkhcu42pSkU9AanLOoBKWfpoyiX5Ql+pStY45Ftz3HPF/NR9bybjwioce6bPgVtejac9AYICgQ0NpYCXHloYGkY5OrbeN1BodNOq4jeEVWp4ZJSVm3bH1CJjIlBJEIi4JETULBCkgF96aBrH1rs7O7jnivl0tOWRkPOGhkdSF+RMhm0vUwxBcpGtDK4XCwQpEJQemsbqn92dHWxbsZgfrvkEHSHrDdIW5ExGDfaCjgU/35qH3/3zRAcBsECQCkELtNJe/TMsqymNQc5k0JZV4c8nvCfgsUCQAklMD41Cd2cHM47zX8Gd9iBnmtxgL6z7aHgpmq7PpCIIgAWCROobKLBozVbmrfg2i9ZsBZgwtt7Rlm+azJq7Lj+zKYOcaWLP3uoUpgwLAq3HHy1/nwK2sjgOz956dC8EyTkb5QT8kZQWkPMyhO65Yn5DVgnXmxfMSlNjwUk3TXO6rGlCQQXkirXm4fL74mpRJCwQ1FtpapmOHn3sEwzCMoSa9ULY3dkx4XsLCobeucY0TFgBOXDWCjRosVgtbGio3rY/VNXxZsoQmqqgYPil3p2WVmoaK6zisLdgLGVBACIKBCJysYjsEZG9IrLC5/l1IrLDffsXERkqem606LlNUbQnUYK2xtRRZ7JpsHfC4WbNEKpGUNAbVeXmDTv41F9+P+YWGeMKrDicnAJyU1FzIBCRHHA/cAlwBnCNiJxRfI6q3qKqC1V1IfAnwMaip4e951R1Sa3tSRwJWUl7aJ9Tm6QoGDRrhlA1ygW9bT84yB19u2Jqjck8L0NoZRsced+pPDxBsgrITUUUPYJzgL2q+qaqHgEeB5aGnH8N8FgEXzcdzr4h/PmR4Qm5yKWrb5spQ6hSlZSieOzlMjvIGROFCRlC6uxPoupWI3Y3krlifaoyhPxEMVncART/V+4HzvU7UUROBuYBW4sOHysi/cAHwBpV7Qt47TJgGcDcuXNrb3VcvD8QL2vIT8m4Y+nkadZ43/uXencyGlAUMei4MZEZ7PWvITQ2AtOOh9t+GH+b6iTuyeKrgSdVJ1wRT3ar4V0L3Ccip/q9UFXXq2qXqnbNmjUrjrZG57KvwV0H3e3ofCRkp7Mk6e7s4Ks9ZwU+n5OwakXGROD524KfS8g2tVGJIhAUgOIr3Gz3mJ+rKRkWUtWC+/5N4LtAZwRtSqbz73RyjIslvCphI3V3drDo1Hbf5645NyCoGhOVFGxTG5UoAsErwGkiMk9EpuFc7Cdl/4jIR4AZwPeLjs0QkQ+5H88EFgGvRdCmZFrQ49QeKd6oOiW1SBrl0Rt/k+vOmzveA8iJcN15c1ndPb/BLTNNrSSbb5Imu3mLZGMaEbkUuA/IAQ+q6t0isgroV9VN7jkrgWNVdUXR6/4j8BfAGE5Quk9VyxT2zubGNMaYGIXVEWo9Hr78drztiUjQxjSRrCxW1eeA50qO3VnyeKXP6/4ByNStXTPsNJYU9rM0kRvsdbL4wuoIpax8RCWsxESMrHRCdPoGCix/YicjY06PtjA0zPIndgL2szRTVMmew/n2phzKtRITMWqWncaSYOWm3eNBwDMyprbNpZm6LavCg0BrHi65N772xMgCQYysjlB0hoZHqjpuTKjB3vDhoCZP7LChoRh4Y9lB0/JZqiNkTOJ4Q0JBvGJyTcx6BHXWN1Bg+ZM7KQTc9fvWESqubeJTmM4QuLMZOPsYWJVSU7GwIaGMrPOxQFBnX3lmNyOj/n0B3zpC3t2JV9vEpzCdcXY2a835ry72JuEtGJiKhK0SbuLhoGIWCOrsvcPBY9bbViyenOHid3dSUpjOOJlBa688i46AYTWbhDcVC1olPH1OJoIAWCBInqC7kyarbRKF7s4Otq1YTFDVIZuENxWx0i8WCOqtLe8/lh10PPjupLlqm0TJNvMxNbHSLxYI6m3lkjNpbZl4z9raIqxccqb/C+zupGp++xcIzlyBTRybiizocTKDVg6ldrvJWlj6aJ15cwAVl0Lw/gC3rHKGg6bPTuVm2HEq/hkXhoYRjm4vbqu3jSkvkqJzcbOicybIojVbfVN1O9rybFuxuAEtMiY5gorO2dCQaSq2etuY6lkgSAtbZFYRmzg2pnoWCNLAFplVzG/i2Hf1tjFmXCSBQEQuFpE9IrJXRFb4PH+DiBwQkR3u22eLnrteRN5w366Poj1NxxaZVay7s4N7rphPR1seIWD1tjFmgpqzhkQkB9wPfBzYD7wiIptUtXTLyQ2qelPJa9uBu4AunESP7e5r36u1XU3FFplVpbuzwy78xlQhih7BOcBeVX1TVY8AjwNLK3ztRcALqnrQvfi/AFwcQZuaiy0yM8bUURSBoAMoLuS93z1W6vdEZFBEnhSROVW+NttskZkxpo7iWlD2DPCYqv5CRP4z8DBQVVK3iCwDlgHMnTs3+hYmmS0yq5ntb2xMsCgCQQGYU/R4tntsnKr+rOjhA8D/LHrtb5e89rt+X0RV1wPrwVlQVkuDU2lBj134p8j2is6w8c3o7QYqTBRDQ68Ap4nIPBGZBlwNbCo+QUROLHq4BHjd/XgzcKGIzBCRGcCF7jFjImN7RWeUpV1XrOZAoKofADfhXMBfB3pVdbeIrBKRJe5pXxSR3SKyE/gicIP72oPAf8cJJq8Aq9xjxkTGVhtnlKVdVyySOQJVfQ54ruTYnUUf3w7cHvDaB4EHo2iHMX5Oasv71h+y1cZNztKuK2Yri03Ts9XGGWVp1xWzMtSm6VVdCtyk2/gE8T6YUJQcS7sOYIHAZIKtNs4Ib4J4fG5AGQ8G0+dY1lAACwTNwtLkjPGfIPaCwC2vNqRJaWCBoBmU3gV5aXJgwcBki00QT4lNFleob6DAojVbmbfi28nbB9fS5Ixx2ATxlFggqMAdfbu4ZcMOCkPDKEdXpiYmGNhdkDEOq8s1JRYIyugbKPDoS29RWtMiUStT7S7IGMeCHrj8G86cAOK8v/wbNkRahs0RlLF2855JQcCTmJWp599ZkimB3QWZ7PBLlLCJ4apYj6CMsIt9Ylamlt4F5dvhmDxsXGb7G5vmZvWEImGBIETfQIEWEd/nBJK1MnVBj3MXdMV6+GAYhg9i/xjVSXRCgPH3/G2WKBEBCwQBvNLFozp5YEiAT503N5kLlCyDaEq833diEwLMZM/e6t7w+LBEiapYIAjwlWd2TypdDJATYd1VC1ndPb8BrapAYAbRPusVhLBS1Skz2Av9IbUqLVGiKhYIfPQNFHjv8Ijvc2OqyewJeML+AWyIKJCVqk6ZLasgMI0DS5SokgUCH2F3gYmZIA7il0ftsSGiQEG/18T/vrMqbOgn327polWyQOAj7C4wURPEfrwMoiA2durLSlWnTGDPV+CSe2NtSjOIJBCIyMUiskdE9orICp/nbxWR10RkUES2iMjJRc+NisgO921T6WsbIegusC3fmuxhIc+CHjeV1IeNnfrq7uzgnivm09GWR4COtjz3XDE/Hb/vLPLt+Qp0fdp6A1NQ84IyEckB9wMfB/YDr4jIJlV9rei0AaBLVQ+LyH/B2bz+Kve5YVVdWGs7orT8otMnbHYOzt3hyiVnNrBVVbJFZlWzUtUp4l3sreJuJKJYWXwOsFdV3wQQkceBpcB4IFDVF4vOfwm4LoKvWzdNsZGJ/aPUrG+gkO6/gWa3oMf+niMi6pMnX9UnELkSuFhVP+s+/n3gXFW9KeD8PwV+rKqr3ccfADuAD4A1qtoX8LplwDKAuXPnnv2jH/2opnZnju1XUBVvXUFpr9CGi0yaich2Ve0qPR7rZLGIXAd0AWuLDp/sNuxa4D4ROdXvtaq6XlW7VLVr1qxZMbS2idgy/KrZugKTJVEEggJQPDM52z02gYhcAHwZWKKqv/COq2rBff8m8F2gM4I2mWK22rhqtq7AZEkUgeAV4DQRmSci04CrgQnZPyLSCfwFThB4t+j4DBH5kPvxTGARRXMLJiK2X0HVbF2ByZKaA4GqfgDcBGwGXgd6VXW3iKwSkSXuaWuBXwKeKEkT/XWgX0R2Ai/izBFYIIhaUMqotNjwUABbV2CypObJ4kbo6urS/v7+RjcjPUr3NC7WmreNOwIUZw1Nz7ciAkOHRyyDyKRW0GRx5gNBZlIEB3vhqc+BTi6kx/Q5tpFHCMsgMs0iEVlDSZOp0sMLekDH/J+zuYJQlkFkml2mA0Hm/sFtb+MpsQwi0+wyHQgy9w8eVJn0yPs2aRwiKFOoRaQ5e48mczIdCDKXIuhVJs23Tzw+fNAWmIXwyyACGFVt3qFEkymZDATe3rSFoWFKdyRu+hTBBT0w7fjJx0eGnclkCwaTeJVJcz77Vw+PjLJy0+4GtMqY6GQuEBRPEIOzx5H3752Z0sNBk8M6Cn2ft2Dgo7uzg7GADLuh4RHrFURpsBfWfRRWtjnv7e+x7jIXCPwmiBUnCGxbsbj5gwCETw6PjcDzt8XXlhQJGzJs2gSDuFldrIbIXCDI3ASxn7DtLMGZMzCThA0ZZurvp56sLlZDZC4QZG6C2E+57SyNr+7ODmYc1+r7XKb+furJ6mI1ROYCgdWQcS3omZw95Ak6brjr8jPt76eebK1LQ2QmENzRt4tTb3+Omzfs4N9GRjl+Ws72pr3kXshNm3gsN802/w5RurdxW76VY1tbuGXDDhat2WqTxrXyG7a0LVbrLoqtKhPvjr5dPPLSW+OPFXj/yCjXnTeX1d3zG9ewRrPtLKfE29u4tAaRV6LEO8dMgf1NNkQmis6devtzjPp8nzkRfnDPpVE2Lf1sS8uKeWtRSnkZaKZC9jcXm6Cic5noEfgFgbDjmVVartpL3QP7x/RhGWgRGOyFp78Ao0ecx4f2OY/B/uZilIk5Ar8VoWHHM8tS96piGWgReP62o0HAM3rE1rLELJJAICIXi8geEdkrIit8nv+QiGxwn39ZRE4peu529/geEbkoivaUuubcOVUdzyxL3auKZaBFIGjNiq1liVXNgUBEcsD9wCXAGcA1InJGyWmfAd5T1V8D1gH3uq89A2eP4zOBi4E/cz9fpFZ3z+e68+aO9wByIjZR7MdS96pSmkGU6Qw0k2pRzBGcA+xV1TcBRORxYCkTN6FfCqx0P34S+FMREff446r6C+CHIrLX/Xzfj6BdE6zunm8X/nLOv3PylpaWuhfKyyAyU5Rv97/7t7UssYpiaKgD2Ff0eL97zPccd7P7Q8CHK3wtACKyTET6RaT/wIEDETTbTOKtOJ4+BxDnve1nbOolqH5QS6utZYlZarKGVHU9sB6c9NEGN6d5LeixC7+pv9IMNU++3QkC9jcYqyh6BAWgeNZ1tnvM9xwROQaYDvyswteaRrKSwKYe/DLUwNkrw4JA7KIIBK8Ap4nIPBGZhjP5u6nknE3A9e7HVwJb1VnJtgm42s0qmgecBvxjBG0yUbCSwKZeLEMtUWoeGlLVD0TkJmAzkAMeVNXdIrIK6FfVTcA3gb9xJ4MP4gQL3PN6cSaWPwC+oKqjvl/IxC9sXYHdtZlaTJ/t3mD4HDeT9A0UWLt5D28PDXNSW57lF50eaZJCJHMEqvoc8FzJsTuLPv434JMBr70buDuKdpiI2V2bqRfLUKtYHDWtMrGy2EyRrSuoibc39rwV37bKpKUsQ61ifrsqDo+MRrorXmqyhkwD+N21ARx535knsH/aQH0DBZY/sZORMSfBrTA0zPIndgJWmXScZahVJI6aVtYjMMG8u7bSxT3DB23SuIyVm3aPBwHPyJiyctPuBrXIpFUcNa0sEJhwC3qclL5SVowu1NDwSFXHjQkSR00rCwSmPJs0jpTNFZhqxFHTyuYITHmW6le1Gce18t5h/7t/mysw1ap3TSvrEZjybB/Zqt11+Zm05vz3u7C5ApM0FghMeZbqV7Xuzg7WXnlW4PM2V2CSxIaGTGUs1a9q3Z0d3LxhR6ObYVKm3quI/ViPwJg6mnFca1XHm4oVLKyat4q4MDSMcnQVcb0TDCwQGFNHfnMFrTnhrsvPbFCLYmIFC6ckjlXEfiwQGFNH3lxBcerf2ivPav6MobCChSZQHKuI/dgcgTF1lsntLP3SjcHWnpRxUluegs9FP8pVxH6sR2CMidZgL+CfOmtrT8LFsYrYj/UIjGmARmSGxGbLKsBvN1mxtSdleH8Dcf9tWCAwJmZx1JdvqMDhH7UU5Ao0YiixpqEhEWkXkRdE5A33/QyfcxaKyPdFZLeIDIrIVUXPPSQiPxSRHe7bwlraY0waNCozJDaB+1jM8T+ecUnYt6LWOYIVwBZVPQ3Y4j4udRj4T6p6JnAxcJ+ItBU9v1xVF7pvO2psjzGJ16jMkLrz1g0c2sekOQIrSeKrb6DA8id3Tlg3sPzJnbEHg1oDwVLgYffjh4Hu0hNU9V9U9Q3347eBd4FZNX5dY1IrjvrysZuwbgCcOQI3GFhJkkBfeWY3I6Ml+1aMKl95Jt5aVLUGghNU9R334x8DJ4SdLCLnANOAHxQdvtsdMlonIh8Kee0yEekXkf4DBw7U2GxjGqdRmSF19fxtk9cNoE4QuOVVCwIBgirUBh2vl7KBQES+IyKv+rwtLT5PVRX/VAHv85wI/A3wB6o65h6+HfgI8BtAO3Bb0OtVdb2qdqlq16xZ1qEw6VVaX74t38qxrS3csmFHOvc2Hux1dq3zY+sGUqFs1pCqXhD0nIj8REROVNV33Av9uwHn/TLwbeDLqvpS0ef2ehO/EJG/Av6oqtYbk1JeZkhTZBCFrRa2dQOh2vKtvpVo2/Lx1qKqdWhoE3C9+/H1wNOlJ4jINOAp4K9V9cmS50503wvO/MKrNbbHmFRpigyisLt+myAOtXLJmbS2lNSiahFWLom3FlWtgWAN8HEReQO4wH2MiHSJyAPuOT3AbwE3+KSJPioiu4BdwExgdY3tMSZVUp9BNNgLEnAZybfb3EAZ3Z0drP1kSS2qT8Zfi6qmBWWq+jPgfJ/j/cBn3Y8fAR4JeP3iWr6+MWnXqNoykfAyhXR08nOtebjk3vjblEJJqEVltYZMfQz2wr3zYOV05+3eeVaC2EeqM4h8M4UAyVm6aMpYiQkTvcFe6Ps8jBVNgg0fhKe/4HxsF4hxjaotU7OwTCEds99xylggMNHbsmpiEPCMHnGes4vEBEkYGqiaZQo1FQsEJnphWSSWV94cLFOoakmuOGuBwERv+uzgjUnsbrEid/Tt4rGX9zGqSk6Ea86dw+ru+Y1u1lFBv2PLFPJ1R98uHn3prfEVt0lbL2KTxSZ6598JLQELYo68b5PGZdzRt4tHXnqLUXUuG6OqPPLSW9zRt6vBLSty/p1OZlAxyxTy1TdQmBAEPElaL2KBwERvQQ90/5lzd1hq+KBtYl7GYy/796aCjjfEgh4nM2j6HECssFyItZv3BNbeScp6ERsaMvWxoMd5Gy9LXMTbxNwuGr68nkClxxvG+x2bUGEX+6SsF7EegamvoElFmzQOlBP//X6DjptkC7rYCyRmvYgFAlNfgbtV2aRxkGvO9d/Ja1Q1ndVJM85v0aAAnzpvbiImisECgam3oElFSzEMtLp7PtedN9e3B+Blm1gwSI/SsuMdbXnWXbUwUVlgokkbd6xAV1eX9vf3N7oZplKDvc6cwKH9kHe3tR5+z+kVnH+njTOHWLRmq28too62PNtWxFSq69lbYftDTk0hycHZN8BlX4vna6dUUtcMiMh2Ve0qPW49AlN/C3qcXaquWA8fDLulCdSZRLYMolANr0767K3Q/82jheV01Hn87K3xfP0U8vaYKN6HOOm9OAsEJj5bVk0uUuZlEBlfDd/fePtD1R03qdxjwgKBiY9lEFWt4dVJ/UpMhx03je/FTUFNgUBE2kXkBRF5w30/I+C80aJNaTYVHZ8nIi+LyF4R2eDuZmaalWUQVc1vovGeK+bHN94sueqOm8b34qag1h7BCmCLqp4GbHEf+xlW1YXu25Ki4/cC61T114D3gM/U2B6TZJZBNCXdnR1sW7GYH675xPgE8aI1W5m34tv1Tyc9+4bqjmdc30CB93/xwaTjSd9jotZAsBR42P34YZx9hyvi7lO8GPD2Ma7q9SaF/MoSnHWtM0ewss1ZhWwTx6Fim4gc7HV+H/0PQuvxR7ejlBx0fcayhnx4v5vSzehnHNcaby9uCmotMXGCqr7jfvxj4ISA844VkX7gA2CNqvYBHwaGVNULn/uB5P6kTDSKyxJ4Wx16E8heFpF3npkkbCIysgvNs7c6AcCrkDPyvtNzs1pCgfoGCnypd6dvGZDjph2T6CAAFfQIROQ7IvKqz9vS4vPUWZAQtCjhZDd39VrgPhE5tdqGisgyEekXkf4DBw5U+3KTRJZFVLWgCcfC0HA0vYLB3olBwGO/l0B9AwWWP+kfBCDZk8Sesj0CVb0g6DkR+YmInKiq74jIicC7AZ+j4L5/U0S+C3QC3wLaROQYt1cwGwj8S1bV9cB6cBaUlWu3SYHALKIEVdlMmKDN7oFo6ttvWUXg/Zxld/n6yjO7GRkNviQleZLYU+scwSbgevfj64GnS08QkRki8iH345nAIuA1twfxInBl2OtNEwvMFhKbKwjgl07qqTlXfbA3PAhbdpev9w77bMvqSvoksafWQLAG+LiIvAFc4D5GRLpE5AH3nF8H+kVkJ86Ff42qvuY+dxtwq4jsxZkz+GaN7TFpcv6dOOW3SqkNQwTw0kmDTHkYwpuvCSSW3eWj3HBc0ieJPTVNFqvqz4DzfY73A591P/4HwPcvV1XfBM6ppQ0mxRb0wMYb/Z+zYYhA3Z0drN28x3eIaMrDEH7zNeMEuj5tE8U+wnpgbfnWVAQBsJXFptGm+5dctmGIcJGvOA4LvFest3TRAGE9sJVLzoyxJbWxQGAayxaZTUnkK44DV33PsZ5AiKAeWJp6A2BbVZpG8y4yXplqK01dse7OjuguNuffOXFNB1hADuGVmS4MDSNMzLPKt+ZS1RsACwQmCWzv20jUVAPfAnLF7ujbxaMvvTV+8VcYDwYdCdp7oBoWCEwyFW9mYxelsrzyBt6qY6/0BFSxrsACcll9A4UJQcDjBYHYNguKmM0RmOTxUhkP7cM2sKlMGmvgp9HazXsCyyekYQVxEAsEJnmCSk889TkLBgGqKj3hFZSzQn9VC7vYp2EFcRALBCZ5glIZdRQ2LrNtEn2EXYQmVCe13lZNgn7OAqlYQRzEAoFJntA1BOrsmWsXrgnKlZ74Uu9OJxhYob+a+P2cBfjUeXNTN0FczAKBSR6/tQWlnr8tnrakRLnSE6Oq3L5xF2rbhVatb6AwvhHQ2s17+L2zOyas31h31UJWdwf/7NPAsoZM8niZK099Lnhv3OGD8bUnJcJKT4DTM/hJbia/ik8Zd1vJ7etTf/l9tv3g6N9aYWiYb20vpKaGUKWsR2CSaUEP/O6fN7oVqRM0RLSk5Xt8b9oX+RU9wKRCf7ZwzNcdfbsmBAFPM2ZjWSAwybWgB6Yd7/9cvj3etqSEN0SUk6MX+yUt32NN6wPMbvkpLQJHl0DhlJCwncd8/e3LbwU+l+ZUUT8WCEyyXXYf5KZNPJabBpfc25DmpEF3Zwdf7TlrvGfwx8f0cpwcKTlLnSBwy6sWBHz0DRQYC9n+Ks2pon5sjsAkm5U+mBJv/Hrt5j2cNPxT33P00H7f3SBMeHlpSHeqqB8LBCb5rPTBlHhF6X68cpbvBPFPmMmvNqBdaRA29LPo1PammiiGGoeGRKRdRF4QkTfc9zN8zvkdEdlR9PZvItLtPveQiPyw6LmFtbTHZIytkA3n/nx+RQ9MGuY4rNO458gnG9OuBPNSRYNGhfKtLTx642/G2qY41DpHsALYoqqnAVvcxxOo6ouqulBVFwKLgcPA3xWdstx7XlV31NgekxWDvdD3+YkrZPs+b8HAU7SCuEWgRWBMQRX2j81kxchneXrsYyxas7XsdotZ4RXuC0q/zbfmuOeKBTG3Kh61BoKlwMPuxw8D3WXOvxJ4XlUP1/h1TdY9fxuMlWwaPjZiC83ACQJPfW7SCuIWgYLO5GNHvsGmsY8BR6uUZj0Y9A0U+FLvzkmF+zw1b/yTcLUGghNU9R334x8DJ5Q5/2rgsZJjd4vIoIisE5EPBb1QRJaJSL+I9B844LMgxmRL0IKyrC8083oCAQvxTpKfTTrWjHnx1fB6AqPqPyAkwLYVi5s2CEAFgUBEviMir/q8LS0+T1UVAofWEJETcTax31x0+HbgI8BvAO1A4O2cqq5X1S5V7Zo1a1a5Zpssy+p8QUBPoNjb+mH/402WF18NvxLexZotVdRP2awhVb0g6DkR+YmInKiq77gX+ndDPlUP8JSqjvfni3oTvxCRvwL+qMJ2m6zLtwff/XsVNSE72UZlegIAtOZ5QK+D0iUFZONiFyQsCOZbc02XKuqn1qGhTcD17sfXA0+HnHsNJcNCbvBARARnfuHVGttjsuKSeycvNCuWtYqaflVFi0kOLv8GCz+xbFIJiqxc7IIEBcGcSFPPCxSrNRCsAT4uIm8AF7iPEZEuEXnAO0lETgHmAP+n5PWPisguYBcwE1hdY3tMVizogaX3O6tjg2SpombY99qad+o2LegZL0FRXD0zKxe7IH71mfKtOb7ac1Zmfi6iARMkSdbV1aX9/f2NboZJinUfddNIfUyfk42VyEE/A8mNBwETrG+gwNrNe3h7aJiTUroBfSVEZLuqdk06boHApJ43Ph40NNKab/7Can4/gyq/76xcDLPMAoFpboO9bj2ikJ7BLU02BTX+Pbs1mE67EN74uynVZPJSKEuzZ2Yc18pdl59pAaFJWCAw2bCyDf8sZoGVQ/G2pV4Ge52Fc6VZUzX0fBat2Rq4otbbijHtu3CZ4EBgZahNcwnaaatZduDyhoD8UmdryJQKS6FU4NGX3sr86uNmZoHANBe//Y5b886wSTMUqCuXJjrFTKly6wiU8qWZTXpZIDDNZUGPMzwyfQ4gzvuzroWdfzuxQN0zX0xnMCh3oZ9izydoi8tihaFhTr39Oe7o2zWlr9EIxRvPW4G9YLYfgWk+pfsXrPvo5LtobxglDZlExZPC0hK8eriGvYe9yeCVm3YzNDwSeN6oKo+85GzhmPQ5g9IJcK/AHmCT3yWsR2CaX9BddBoWnBWVkwYNDgL59ppTZLs7O9hx14Vcd97csjuXPfZyQHZWAni9gJs37JiUBZX1AntBrEdgmt/02f5ppUmeQC6XDis50LG6bN25uns+XSe3s3bznsBMoqBKnY0WlAZbLMsF9oJYj8A0v6AJ5CkOo9TdYC88/YXgIABOEFg5VLfN57s7O9i2YjE58e8bBB1vtHKVRCHbBfaCWI/AND/vQlm8+CrJZSeevw1GfUqEFoupN3PNuXPG5wRKjydlJXJxO8r1U7JeYC+IBQKTDaUTyH5KV+o2KliU21wnxt6MNyH82Mv7GFUlJ8I1586h6+T2SROxt2zYQf+PDsY2iewMAw0yPDJW0fkdVjYjkK0sNgYiqdVT09cuDkBhQ0IJKaIXthIZ6l+aom+gwPIndjIyVv765ew1nO0Kq56glcXWIzAG/BdqjQw7O35tXBZ9D2HCZLAwXhYjLAjk2xNTL6nchOt7h0dY/uROoD6pmms37ykbBASseF6FLBAYA8GppF665qF9TkDYeGPtd+WTeh8V9MpbWp3NeBLipLZ8aI8AYGRUuXnDDm7esCPyHkK5QNTRlmfbisWRfK0ssEBgDJQfkgEm3LVvvNF5y7c7F2i/oOCXAio5aD02vEzEeJvmNH6+IsDyi07nlg07KglhQHU9hEomocMCkbjtM5WraY5ARD4JrAR+HThHVX0H7kXkYuDrQA54QFW9nczmAY8DHwa2A7+vqmXSJWyOwNRBuT0NKlHcU/BSQMtl/4R9roQMAwW5o28Xj770VsXBACbeqXsX/OILugAtLcJo0bCP3xh/2BzBdVYpNVC9qo++ClwB/H3IF84B9wOXAGcA14jIGe7T9wLrVPXXgPeAz9TYHmOmprRGkYTX3fFVXMOokhTQIEle41Bkdfd81l21kLZ8a8Wv8YZ0vIVfpXf1ChOCAPivBu7u7GDtJ8+a8LVnHNfKfVcttCAwBTUNDanq6wASvrjkHGCvqr7pnvs4sFREXgcWA9e65z2M07v4X7W0yZgpK04xnWoPwathVC4FdBJ3wjghWUGV6u7soLuzg76BQtk6RXB0MVclC7+K+c0JeF/b1C6OOYIOoHjwdT9wLs5w0JCqflB0PPC3KiLLgGUAc+fOrU9LjfFMWIRWktlTTkU1jMSdl0jmHEC1ii/KQcM2rTkZH7uvtsyDrQaur7KBQES+A/yqz1NfVtWno2+SP1VdD6wHZ44grq9rMqy0h+C3K5if6bPhyPvh53Z9Gi77WjTtTBi/SqalWUOVZB15bDVw/ZUNBKp6QY1fowDMKXo82z32M6BNRI5xewXecWOSxwsK5QJC8fh+3+dhrGSoRFrg7D9o2iDgKTdss/yi00OLwx0/LcfhI6O2DiAmcQwNvQKc5mYIFYCrgWtVVUXkReBKnMyh64HYehjGTElpqYpyZSmSULIigbwLe2nWkFfCwiZ841Vr+ujvAn8CzAKGgB2qepGInISTJnqpe96lwH046aMPqurd7vF/jxME2oEB4DpV/UW5r2vpo8YYU72g9FGrNWSMMRlRr3UExhhjUs4CgTHGZJwFAmOMyTgLBMYYk3GpnCwWkQPAj6p82Uzgp3VoTtLZ950t9n1nS7Xf98mqOqv0YCoDwVSISL/fbHmzs+87W+z7zpaovm8bGjLGmIyzQGCMMRmXpUCwvtENaBD7vrPFvu9sieT7zswcgTHGGH9Z6hEYY4zxYYHAGGMyrukDgYhcLCJ7RGSviKxodHviIiIPisi7IpLsHdAjJCJzRORFEXlNRHaLyB82uk1xEJFjReQfRWSn+31/pdFtipOI5ERkQESebXRb4iIi/yoiu0Rkh4jUXIGzqecIRCQH/AvwcZytMF8BrlHV1xrasBiIyG8BPwf+WlU/2uj2xEFETgROVNV/EpF/B2wHupv99y3OpuHHq+rPRaQV+B7wh6r6UoObFgsRuRXoAn5ZVS9rdHviICL/CnSpaiSL6Jq9R3AOsFdV31TVIzh7HyxtcJtioap/D1S7g3qqqeo7qvpP7sf/D3idkH2wm4U6fu4+bHXfmvcOr4iIzAY+ATzQ6LakWbMHgg5gX9Hj/WTgwmBARE4BOoGXG9yUWLjDIzuAd4EXVDUT3zfOhld/DIw1uB1xU+DvRGS7iCyr9ZM1eyAwGSQivwR8C7hZVf9vo9sTB1UdVdWFOHt/nyMiTT8cKCKXAe+q6vZGt6UBPqaq/wG4BPiCOxQ8Zc0eCArAnKLHs91jpkm5Y+TfAh5V1Y2Nbk/cVHUIeBG4uMFNicMiYIk7Xv44sFhEHmlsk+KhqgX3/bvAUzjD4FPW7IHgFeA0EZknItOAq4FNDW6TqRN30vSbwOuq+rVGtycuIjJLRNrcj/M4yRH/3NBGxUBVb1fV2ap6Cs7/9lZVva7Bzao7ETneTYZARI4HLgRqyg5s6kCgqh8ANwGbcSYOe1V1d2NbFQ8ReQz4PnC6iOwXkc80uk0xWAT8Ps6d4Q737dJGNyoGJwIvisggzs3PC6qamVTKDDoB+J6I7AT+Efi2qv7vWj5hU6ePGmOMKa+pewTGGGPKs0BgjDEZZ4HAGGMyzgKBMcZknAUCY4zJOAsExhiTcRYIjDEm4/4/Uzw7NhstAVwAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "arr = np.sort(np.random.rand(100) * 5)\n",
    "arr_sin, arr_cos = to_sincos_time(arr, 5)\n",
    "plt.scatter(arr, arr_sin)\n",
    "plt.scatter(arr, arr_cos)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def plot_feature_dist(X, percentiles=[0,0.1,0.5,1,5,10,25,50,75,90,95,99,99.5,99.9,100]):\n",
    "    for i in range(X.shape[1]):\n",
    "        ys = []\n",
    "        for p in percentiles:\n",
    "            ys.append(np.percentile(X[:, i].flatten(), p))\n",
    "        plt.plot(percentiles, ys)\n",
    "        plt.xticks(percentiles, rotation='vertical')\n",
    "        plt.grid(color='gainsboro', linewidth=.5)\n",
    "        plt.title(f\"var_{i}\")\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "arr = np.random.rand(10, 3, 100)\n",
    "plot_feature_dist(arr, percentiles=[0,0.1,0.5,1,5,10,25,50,75,90,95,99,99.5,99.9,100])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "IPython.notebook.save_checkpoint();"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "001_utils.ipynb saved at 2021-11-23 13:16:49.\n",
      "Converted 001_utils.ipynb.\n",
      "\n",
      "\n",
      "Correct conversion! 😃\n",
      "Total time elapsed 0.009 s\n",
      "Tuesday 23/11/21 13:16:52 CET\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "                <audio  controls=\"controls\" autoplay=\"autoplay\">\n",
       "                    <source src=\"data:audio/wav;base64,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\" type=\"audio/wav\" />\n",
       "                    Your browser does not support the audio element.\n",
       "                </audio>\n",
       "              "
      ],
      "text/plain": [
       "<IPython.lib.display.Audio object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#hide\n",
    "from tsai.imports import create_scripts\n",
    "from tsai.export import get_nb_name\n",
    "nb_name = get_nb_name()\n",
    "create_scripts(nb_name);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
